1

I'm trying to test a Room DAO exposing functions that return Flows. The following test won't pass and I'm struggling to see why :

    @Test
    fun `observeHomeCoursesFeatured() does not return courses that are no longer featured`() = runBlocking {
        val outputList: MutableList<List<HomeCourse>> = mutableListOf()
        launch { subject.observeHomeCoursesFeatured().collect { outputList.add(it) } }

        subject.saveHomeCoursesFeatured(listOf(getHomeCourseFeatured1(), getHomeCourseFeatured2()))
        subject.saveHomeCoursesFeatured(listOf(getHomeCourseFeatured1()))

        assertEquals(2, outputList.size)
        assertEquals(listOf(getHomeCourseFeatured1(), getHomeCourseFeatured2()), outputList[0])
        assertEquals(listOf(getHomeCourseFeatured1()), outputList[1])
    }

It fails at assertEquals(2, outputList.size) saying that outputList is empty.

This test passes :

    @Test
    fun `observeHomeCoursesFeatured() does not return courses that are no longer featured`() = runBlocking {
        subject.saveHomeCoursesFeatured(listOf(getHomeCourseFeatured1(), getHomeCourseFeatured2()))
        assertEquals(listOf(getHomeCourseFeatured1(), getHomeCourseFeatured2()), subject.observeHomeCoursesFeatured().first())

        subject.saveHomeCoursesFeatured(listOf(getHomeCourseFeatured1()))
        assertEquals(listOf(getHomeCourseFeatured1()), subject.observeHomeCoursesFeatured().first())
    }

The second test passing, shows that my DAO is working fine and it is more a question of threading and concurrency between the test thread and the thread that Room uses to trigger Flow changes.

I already added @get:Rule val archRule = InstantTaskExecutorRule() in my test. I also build my test DB with this :

db = Room.inMemoryDatabaseBuilder(ctx, CoreDatabase::class.java)
            .setTransactionExecutor(Executors.newSingleThreadExecutor())
            .allowMainThreadQueries()
            .build()

What am I missing ?

2 Answers 2

1

launch is asynchronous, so you have a race condition.

@Test
fun `observeHomeCoursesFeatured() does not return courses that are no longer featured`() = runBlocking {
    val job = async { subject.observeHomeCoursesFeatured().take(2).toList() }

    subject.saveHomeCoursesFeatured(listOf(getHomeCourseFeatured1(), getHomeCourseFeatured2()))
    subject.saveHomeCoursesFeatured(listOf(getHomeCourseFeatured1()))

    val outputList = job.await()

    assertEquals(2, outputList.size)
    assertEquals(listOf(getHomeCourseFeatured1(), getHomeCourseFeatured2()), outputList[0])
    assertEquals(listOf(getHomeCourseFeatured1()), outputList[1])
}
Sign up to request clarification or add additional context in comments.

4 Comments

Now my test won't finish because runBlocking { subject.observeHomeCoursesFeatured().collect { outputList.add(it) } } runs endlessly. And that's normal, that's why I think I have to launch a coroutine using launch
It's the same thing. My test won't end because join() waits for the coroutine to finish which it won't by itself because I'm calling collect() on a never ending Flow generated by Room.
Didn't realise it was a never ending Flow. Another update.
Instead of runBlocking, kotlinx.coroutines.test.runTest could be used here. Followed by passing and using the testDispatcher & backgroundScope to collect on the DAO's flow.
1

For this case I recommend to use flow.first()

@Dao 
interface TreeDao{ 

     @Query(Select * from tree) 
     fun getTrees():Flow<List<Tree>>}
}

For example Repository

class Repository(context:Context){
  db = Room.inMemoryDatabaseBuilder(context, TreeDatabase::class.java)
            .build()

fun getTrees():Flow<List<Tree>>
}

Because of any flow is endless than for our testing we can take first value of flow.

@Test
fun GetList()=runTest{
  val list=repository.getDao().getTrees().first()
  Assert.assertEqual(1,list.size)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.