Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android unit testing flow with multiple emit

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?

like image 935
Ma2340 Avatar asked Mar 31 '20 08:03

Ma2340


People also ask

What is SharedFlow?

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 .

What is runBlockingTest?

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.

What is the use of ViewModel in local unit tests?

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.

When to write unit tests in Java?

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.

How to test Kotlin flows on Android?

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 ...

What are local unit tests with JUnit 5?

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.


Video Answer


1 Answers

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")))
}
like image 155
Glenn Sandoval Avatar answered Oct 24 '22 11:10

Glenn Sandoval