I need some help about writing unit tests in android, related to the viewmodel, livedata and flow mechanics and dispatching.
First of all, im writing unit tests, and not instrumeted test.
Actually, im creating an Unit test for an android app, for testing a ViewModel that uses a repository for fetching some data from internet.
The code for the viewmodel im using is like this:
class ViewModel(private var repository: Repository? = Repository()) :
androidx.lifecycle.ViewModel() {
val data: LiveData<Result<Item>> = repository!!.remoteData.asLiveData()
}
The unit test code is as follows:
import junit.framework.TestCase
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.setMain
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.junit.MockitoJUnitRunner
@ExperimentalCoroutinesApi
@RunWith(MockitoJUnitRunner::class)
class ViewModelTest : TestCase() {
private val testDispatcher = TestCoroutineDispatcher()
private lateinit var repository: Repository
private lateinit var viewModel: ViewModel
@Before
public override fun setUp() {
Dispatchers.setMain(testDispatcher)
repository = mock(Repository::class.java)
viewModel = ViewModel(repository)
}
@After
public override fun tearDown() {
super.tearDown()
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
@Test
fun `remote data is returned`() = runBlockingTest {
try {
`when`(repository.remoteData).thenReturn(
flowOf(Result.success(Item(SampleData.remoteData.apiResult!!)))
)
viewModel.data.observeForever { result ->
assertTrue(result.isSuccess)
}
} catch (exception: Exception) {
fail()
}
}
}
When creating the unit test, and running it, the following error happen:
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method androidx.lifecycle.FlowLiveDataConversions.asLiveData, parameter $this$asLiveData
As for the error, it seems that i need to pass a parameter to the viewmodel.data value, but, which one? as per the code, it not need parameters.
I like to know about mocking the methods that returns a flow object, as the asLiveData() function is the one that, when running the test, throws the exception above.
Also, i think i need to know about the observeForever function for executing and observing values from the livedata, after all, is then observing where i can assert the results of the unit test.
Any help would be great. :)
Im using the following libraries in the app build.gradle file:
testImplementation "junit:junit:4.13"
testImplementation "com.squareup.okhttp3:mockwebserver:4.7.2"
testImplementation "org.mockito:mockito-core:3.3.3"
testImplementation "androidx.arch.core:core-testing:2.1.0"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.2"
androidTestImplementation "androidx.test.ext:junit:1.1.2"
androidTestImplementation "androidx.test.espresso:espresso-core:3.3.0"
You need to mock the repository.remoteData
first, and after that you can initialize the ViewModel
`when`(repository.remoteData).thenReturn(
flowOf(Result.success(Item(SampleData.remoteData.apiResult!!)))
)
viewModel = ViewModel(repository)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With