Test methods of Room DAO with Kotlin Coroutines and Flow
Turns out that I wasn't properly handle Flow collection and cancelation and that was probably the cause of problem. Below is the code that works. More complex example can be found here.
@RunWith(AndroidJUnit4::class)
class CoresDaoTest {
private lateinit var database: SpaceDatabase
private lateinit var coresDao: CoresDao
private val testDispatcher = TestCoroutineDispatcher()
private val testCoresList = listOf(core2, core3, core1)
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
@Before
fun setup() {
Dispatchers.setMain(testDispatcher)
val context = InstrumentationRegistry.getInstrumentation().targetContext
database = Room
.inMemoryDatabaseBuilder(context, SpaceDatabase::class.java)
.setTransactionExecutor(Executors.newSingleThreadExecutor())
.build()
coresDao = database.coresDao()
}
@After
fun cleanup() {
database.close()
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
@Test
fun testInsertAndGetAllCores() = runBlocking {
coresDao.insertCores(testCoresList)
val latch = CountDownLatch(1)
val job = launch(Dispatchers.IO) {
coresDao.getAllCores().collect { cores ->
assertThat(cores.size, equalTo(testCoresList.size))
latch.countDown()
}
}
latch.await()
job.cancel()
}
Since you are using the TestCoroutineDispatcher
already, using runBlockingTest
won't do anything in your example..
You will have to cancel
the Flow
after collection or the scope
in which you launched the Flow
edit: an example for such a rule can be found here
To test Flow, the best APIs I found are .take(n).toList()
. You can use runBlockingTest
and you shouldn't need to use withContext
to move the execution to another thread.
You can find an example of how it works here: https://github.com/manuelvicnt/MathCoroutinesFlow/blob/master/app/src/test/java/com/manuelvicnt/coroutinesflow/fibonacci/impl/NeverEndingFibonacciProducerTest.kt#L38