I have my use case that talks to repository and emits multiple data as below -
class MyUseCase(private val myRepoInterface: MyRepoInterface) : MyUseCaseInterface {
override fun performAction(action: MyAction) = flow {
emit(MyResult.Loading)
emit(myRepoInterface.getData(action))
}
}
The unit test for the same looks like this below -
class MyUseCaseTest {
@get:Rule
val instantExecutorRule = InstantTaskExecutorRule()
@Mock
private lateinit var myRepoInterface: MyRepoInterface
private lateinit var myUseCaseInterface: MyUseCaseInterface
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
myUseCaseInterface = MyUseCase(myRepoInterface)
}
@After
fun tearDown() {
}
@Test
fun test_myUseCase_returnDataSuccess() {
runBlocking {
`when`(myRepoInterface.getData(MyAction.GetData))
.thenReturn(MyResult.Data("data"))
// Test
val flow = myUseCaseInterface.performAction(MyAction.GetData)
flow.collect { data ->
Assert.assertEquals(data, MyResult.Loading)
Assert.assertEquals(data, MyResult.Data("data"))
}
}
}
}
After running the test I get this error -
java.lang.AssertionError:
Expected : MyResult$Loading@4f32a3ad
Actual : MyResult.Data("data")
How do I test the use case that emits multiple things?
The shareIn function returns a SharedFlow , a hot flow that emits values to all consumers that collect from it. A SharedFlow is a highly-configurable generalization of StateFlow . You can create a SharedFlow without using shareIn .
runBlockingTest takes in a block of code and blocks the test thread until all of the coroutines it starts are finished. It also runs the code in the coroutines immediately (skipping any calls to delay ) and in the order they are called–-in short, it runs them in a deterministic order.
Once modularized properly, the business logic model, in this case Android’s ViewModel component, and the view interface contract used in production are also used for local unit tests without modification to test the given intents that the model uses to generate the expected view states.
Unit Tests are generally written before writing the actual application. But for the sake of explanation in this article, I am creating a sample app before writing Unit Tests. Unit Testing is done to ensure that the developer would be unable to write low quality/erroneous code.
Testing Kotlin flows on Android 1 Creating a fake producer. When the subject under test is a consumer of a flow, one common way to test it is by replacing... 2 Asserting flow emissions in a test. If the subject under test is exposing a flow, the test needs to make assertions on... 3 CoroutineDispatcher as a dependency. More ...
Local unit tests with JUnit 5 can be run quickly prior to writing a feature and regularly to ensure code quality and mitigate regressions of features’ business logic. These tests do not require dependencies on the Android system. This covers the majority of code for most apps making it a great first step for testing.
You can create a list with the toList
operator. Then you can assert on that list:
@Test
fun test_myUseCase_returnDataSuccess() = runBlockingTest {
//Prepare your test here
//...
val list = myUseCaseInterface.performAction(MyAction.GetData).toList()
assertEquals(list, listOf(MyResult.Loading, MyResult.Data("data")))
}
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