We have a Configuration class and LocalStorage class Configuration takes LocalStorage instance in constructor, LocalStorage takes Context in constructor. We are just trying to start with UI testing.
We are trying to do this
private val localStorage = Mockito.mock(LocalStorage::class.java)
// in our setup method
Mockito.`when`(localStorage.getString(anyString())).thenReturn(str)
Here problem is that getString() method call starts happening immediately when tests are run. We have not even written actual test yet.
Mockito Android version: 3.1.0
I think what problem is may be in Mock final Kotlin classes during UI tests. It is looks like what you use plugin for Mockito to "open" classes.
Possible solutions:
Make LocalStorage to be interface, not class. (5th principle of SOLID, abstraction/realisation). Your problem may disappear because interfaces are open by their nature.
Use Mockk library to mock your LocalStorage and other classes. This framework is better for Kotlin.
Have you considered using alternative approach?
doReturn(str).when(localStorage).getString(anyString())
(import needed: import org.mockito.Mockito.doReturn)
Problem was this LocalStorage was being initialized by our Application class. Mock fails when a dependency is already initialized before. Solution is to create a TestApplication with CustomAndroidJUnitRunner. Make sure dependencies are not pre-initialised and only initialise dependencies as per respective test's requirenment.
Related
The examples online regarding Dagger2 for Android always perform dependency injection inside the onCreate function.
Why not do it inside the constructor of the Activity? It's obviously the earliest point of the object lifecycle.
The earliest point of the object lifecycle, yes, but not of the Android lifecycle. Most things will not yet have been initialized (e.g. the application context will only be set after attachBaseContext() was called)
Depending on what you plan on doing with Dagger (or your project in general) using the constructor might work, but I wouldn't be surprised if some things break.
I haven't done any testing in Android, so please bear with me if this seems a stupid question.
I'm developing an app which makes a lot of network calls from a restful API service. To make the network calls, I'm using Retrofit2 and RxJava.
What would be the best practice/framework to just test if these calls are working? I've started to read the Google Codelab for testing which uses Junit4 and Mockito, but I don't want to do any clicking in the UI to start a test currently, just checking for different API versions which calls are supported or not.
Here some steps for you that I am using:
Use mockito & junit4, for sure :)
I avoid UI tests for these cases
Pass your retrofit Api as a parameter to a class that you want to test
In the test create a mock retrofit api, pass this one as a parameter so you can choose what you want your "Api" to return e.g. objects or errors (see Mockito.when())
Use RxJava's TestSubscriber to test a method e.g. Observable<Location> getLocationFromApi()
Avoid threading in your testing class (e.g. like .observeOn(mainThread())). If inevitable use awaitTerminalEvents in TestSubscriber. If there is no terminal even rethink your test
General tips:
Try to modularize your code so each class has few functionality -> easier to test.
Be patient and don't expect to write tests for e.g. 5% of your code in just one week :) It's a slow process regardless team size
I have an android app that uses ORMLite/SQLite and I use Robolectric in conjunction with JUnit 4 to allow me to run unit tests in Android Studio and on a Jenkins build server.
Typically I would setup test data in my tests, in the setup, and then run my test scenarios against it but when I tried to do this I started getting issues and exceptions which seemed to be related to files being locked or something and that seems to be a problem others have had... so what I have done up until now is use the create database method in my database helper to create some dummy data which the tests expect to be there.
The problem is my application now needs to plug into a real database and I can't have it setup dummy data when it runs.
If there a way, within my database helper class, to detect if the code is executing on a device or within Robolectric?
This is what works well for me on Robolectric 3.
public static boolean isRoboUnitTest() {
return "robolectric".equals(Build.FINGERPRINT);
}
To start with, I'll say that you shouldn't be putting code to initialise dummy/test data in the normal releasable code and in general you shouldn't need to know from the main app if you're in a robo run or not.
Now moving past the disclaimer and to actually answer your question... One way you could to this is to have a method in your application class like this
public boolean isRoboTestRun() {
return false;
}
Then create a "TestApplication" in the test package that extends your normal application and overrides this method to return true.
It's hacky, but that's because it's not really meant to work that way :)
At some point you have to init OrmLiteSqliteOpenHelper with your Context.
Let assume you do this in your application class in onCreate. So just create Test<your application class name> in your tests sources and override onCreate with empty implementation.
Robolectric will find this class and will use during the tests. More details here.
I have an android app that uses ORMLite/SQLite and I use Robolectric in conjunction with JUnit 4 to allow me to run unit tests in Android Studio and on a Jenkins build server.
Typically I would setup test data in my tests, in the setup, and then run my test scenarios against it but when I tried to do this I started getting issues and exceptions which seemed to be related to files being locked or something and that seems to be a problem others have had... so what I have done up until now is use the create database method in my database helper to create some dummy data which the tests expect to be there.
The problem is my application now needs to plug into a real database and I can't have it setup dummy data when it runs.
If there a way, within my database helper class, to detect if the code is executing on a device or within Robolectric?
This is what works well for me on Robolectric 3.
public static boolean isRoboUnitTest() {
return "robolectric".equals(Build.FINGERPRINT);
}
To start with, I'll say that you shouldn't be putting code to initialise dummy/test data in the normal releasable code and in general you shouldn't need to know from the main app if you're in a robo run or not.
Now moving past the disclaimer and to actually answer your question... One way you could to this is to have a method in your application class like this
public boolean isRoboTestRun() {
return false;
}
Then create a "TestApplication" in the test package that extends your normal application and overrides this method to return true.
It's hacky, but that's because it's not really meant to work that way :)
At some point you have to init OrmLiteSqliteOpenHelper with your Context.
Let assume you do this in your application class in onCreate. So just create Test<your application class name> in your tests sources and override onCreate with empty implementation.
Robolectric will find this class and will use during the tests. More details here.
In my android app, there the following code:
BluetoothManager bm = (BluetoothManager)activity.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter ba = bm.getAdapter();
I want to do Unit Tests using Robolectric. I am using Robolectric 2.2.
But I found that bm is null, and I don't know how to mock it.
The challenge
The challenge with testing for bluetooth and other system services is that these classes are all final.
The hard way (skip and go to powermock solution if you like)
So if you want to inject anything else you need to make a wrapper around the final class and then provide an implementation forwarding to actual bluetooth classes and an alternative one that mocks your stuff. But then all coded needs to be updated to use that wrapper instead of the final classes directly.
PowerMock solution
PowerMock however should be able to handle these final classes. The summary (follow link for more detail)
Use the #RunWith(PowerMockRunner.class) annotation at the class-level of the test case.
Use the #PrepareForTest(ClassWithFinal.class) annotation at the class-level of the test case.
Use PowerMock.createMock(ClassWithFinal.class) to create a mock object for all methods of this class (let's call it mockObject).
Use PowerMock.replay(mockObject) to change the mock object to replay mode.
Use PowerMock.verify(mockObject) to change the mock object to verify mode.