Testing LiveData using PowerMockRunner - android

My local unit tests use LiveData all the time. Normally, when you try to set a value on MutableLiveData you get
java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked.
because local JVM has no access to Android framework. I fixed that using that:
#get:Rule
val rule = InstantTaskExecutorRule()
Everything was fine, until I had to use PowerMockito to mock a static method from google play library. Since I added
#RunWith(PowerMockRunner::class)
#PrepareForTest(Tasks::class)
above my test class declaration I started to get this Looper not mocked error again. I used this rule before with MockitoJUnitRunner and everything was fine.

A bit late for the answer, but just faced the same issue and solved it!
To use PowerMock and InstantTaskExecutorRule you need to add the following annotation:
#RunWith(PowerMockRunner::class)
#PowerMockRunnerDelegate(MockitoJUnitRunner::class) //this line allows you to use the powermock runner and mockito runner
#PrepareForTest(UnderTestClass::class)
class UnderTestClassTest {
#get:Rule
var instantExecutorRule = InstantTaskExecutorRule()

No need to fret as it turns out you can still use this method to test your LiveData observers!
First, add this dependency in your module’s build.gradle file:
testImplementation 'android.arch.core:core-testing:1.0.0-alpha3'
Make sure you use the same version as the rest of your android.arch.* dependencies!
Then, in the test class where you need to call setValue() and assert, add this field:
#Rule
public TestRule rule = new InstantTaskExecutorRule();
For Kotlin
#get:Rule
var rule: TestRule = InstantTaskExecutorRule()
Behind the scenes, this bypasses the main thread check, and immediately runs any tasks on your test thread, allowing for immediate and predictable calls and therefore assertions.
Already have this answer here.

Related

Why Hilt isn't necessary for unit tests, but it is necessary for UI tests?

Hilt testing guide documentaton has this paragraph about Unit test
Hilt isn't necessary for unit tests, since when testing a class that uses constructor injection, you don't need to use Hilt to instantiate that class. Instead, you can directly call a class constructor by passing in fake or mock dependencies, just as you would if the constructor weren't annotated:
#ActivityScoped
class AnalyticsAdapter #Inject constructor(
private val service: AnalyticsService
) { ... }
class AnalyticsAdapterTest {
#Test
fun `Happy path`() {
// You don't need Hilt to create an instance of AnalyticsAdapter.
// You can pass a fake or mock AnalyticsService.
val adapter = AnalyticsAdapter(fakeAnalyticsService)
assertEquals(...)
}
}
But here you can see that documentation is explaining how to use Hilt in UI test.
My question is why Hilt isn't necessary for unit tests, but it is necessary for UI tests?
With unit tests you verify behavior inside the classes, while in UI test you verify UI state given data. In unit test you don't need Hilt to generate a object tree, you are testing a small building unit of your app, a class, a function. Your unit test have limited scope of objects needed, so that's another reason why you don't need Hilt to build entire tree of objects each unit test.
In unit test you verify that an event have happened, a function has been called or a result has been returned given an input.
Hilt is injecting fake components in your UI test through which you are providing data that is rendered.

How to set an order in instrumented test over the Test Class?

I'd like to set an order over the Test Class.
#RunWith(AndroidJUnit4::class)
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
class ATest {
#Test
fun test0000()
#Test
fun test0001()
}
#RunWith(AndroidJUnit4::class)
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
class BTest {
#Test
fun test0002()
#Test
fun test0003()
}
I'd like to test ATest.test0000 -> ATest.test0001 -> BTest.test0002 -> BTest.test0003
Because ATest class must be tested before B Test.
How can I do that? Is it possible?
Firstly, I would recommend you to not have any dependencies in Tests.
i.e. Test A class and Test B class should run independently from each other.
This really helps when your application grows.
There should not be a condition that one test should run before another.
Only in a rare / genuine scenario we should have such dependency on sequence.
Because if you design your test with sequence related dependency then it will be difficult for you to maintain your test cases and it will get difficult when you follow Test Driven Development(TDD).
For above case, please try using SuiteClasses.
The SuiteClasses annotation specifies the Suite runner which test classes to include in this suite and in which order.
Please refer to the sample provided by Junit Team HERE

Using InstantTaskExecutorRule causes java.lang.RuntimeException in junit test

I am unit-testing a library that uses a RoomDatabase. Unit-testing the RoomDatabase itself was done using InstantTaskExecutorRule so that LiveData updates can occur instantaneously:
#Rule public TestRule rule = new InstantTaskExecutorRule();
And that works fine. However, when unit-testing the library which calls the database, using the same rule causes the test to throw the exception:
java.lang.RuntimeException: Exception while computing database live data.
...
Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
Is there any reason why InstantTaskExecutorRule works on the underlying database DAOs but not a library calling them?
I am also unit testing a RoomDatabase with Robolectric and the same error occurs while using
#get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
I simply removed it and I'm using runBlocking{ ... } in my tests like this example :
#Test
#Throws(Exception::class)
fun `test insert and retrieve text`() {
runBlocking {
dao.insertText("some text")
assertEquals("some text",dao.getText())
}
}
The only reason I can think of causing this error is a missing ".allowMainThreadQueries()" when building your database:
database = Room.inMemoryDatabaseBuilder(
ApplicationProvider.getApplicationContext(),
myDatabase::class.java
)
.allowMainThreadQueries()
.build()
(Also, testing with databases is recommended to be done as instrumented tests as local tests will use a default SQLite version instead of the version your app is actually using.)

Cannot invoke observeForever on a background thread

I've been using an observeForever() method as described here to test Room and LiveData for a while, and it has worked flawlessly. But when I changed to Android Studio 3.2 (or if it was the androidx refactoring, not sure), that method suddenly stopped working, throwing a
java.lang.IllegalStateException: Cannot invoke observeForever on a background thread
How can we fix this?
I solved it by adding the rule InstantTaskExecutorRule. According to the docs it will
A JUnit Test Rule that swaps the background executor used by the Architecture Components with a different one which executes each task synchronously.
So one needs to add
#get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
to the test class for it to work. The Java equivalent would be
#Rule
public InstantTaskExecutorRule instantTaskExecutorRule = new InstantTaskExecutorRule();
You will also need to add
androidTestImplementation "androidx.arch.core:core-testing:2.0.0"
to your models build.gradle dependencies.
As a beginner to this approach, accepted answer was a little bit vague for me. So just trying to explain it
add this in your build.gradle
androidTestImplementation "androidx.arch.core:core-testing:2.0.0
Now we need to add rule on test function. Lets say that I have a test function writeAndReadCategory then it will look like this in kotlin
#get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
#Test
fun writeAndReadCategory() {
....
}

MVP pattern. Is it a good practice to inject all presenter's dependencies in a constructor of the presenter?

I want my code to be testable and flexible and I cannot make a choice whether I need to pass all dependencies explicitly to a constructor of a presenter or it's better to pass only View interface to a constructor and inject all dependencies in it.
It is a desirable pattern.
Every time you have access to object constructor, you should inject dependencies in constructor or other methods. #Inject annotation is indended mainly to be used inside object, that are not created by you.
When injecting all dependencies in constructor, during tests you pass all your dependencies to your model during initialisation. Therefore every test might contain different dependencies and different instance of created class. That is also the aim of unit tests - provide a sandbox for every test.
It is also easier to mock dependencies with Mockito.
Remember, that in unit tests, you don't have dependency any framework configured. A unit test usually contains created model and nothing more. Everything must be created by you (or mocked by framework)
Here is a sample unit test that proves the statement above:
#RunWith(MockitoJUnitRunner.class)
public class GetAreasUseCaseTest {
#Mock ApiManager mApiManager;
#Mock DatabaseManager mDatabaseManager;
private GetAreasUseCase mGetAreasUseCase;
#Rule
public final RxSchedulersOverrideRule mOverrideSchedulersRule = new RxSchedulersOverrideRule();
#Before
public void setUp() {
mGetAreasUseCase = new GetAreasUseCase(mApiManager,
mDatabaseManager);
doReturn(Observable.empty())
.when(mDatabaseManager)
.insertAreas(any(Area.class));
}
#Test
public void testGetAreasUseCaseApiInteraction() throws Exception {
TestSubscriber<List<Area>> testSubscriber = new TestSubscriber<>();
setCorrectApiResponse();
boolean input = true;
Observable testedObservable = mGetAreasUseCase.build(input);
testedObservable.subscribe(testSubscriber);
verify(mApiManager).getAreas(anyLong());
}
}
As you can see the structure of the test is very clear. It is well known, what is mocked and which object is tested. You have the control of the behaviour of dependencies.
If you plan to do only instrumentation tests, then you are provided with the ApplicationContext in tests and Dagger is properly initialised. There is no difference here. Of course you might still emulate Module's and Component's behaviour and provide custom object's Mocks instead of real classes (Example)
its not a bad practice but its hard to change the code in later changes. what if you want to add a new dependency for presenter ? then you have to change almost everything in your code.
what you are going to do actually is called Dependency Injection and the best practice is to do Dependency Injection, is using libraries like Dagger.
i think Dagger is the most powerful Dependency Injection library up to now. you will write some methods for providing your dependencies and Dagger will provide them for you whenever you want them using a #inject Annotation. for a complete instruction see this link:
http://www.vogella.com/tutorials/Dagger/article.html

Categories

Resources