Room DAO with Kotlin Coroutines and Flow 测试方法
Test methods of Room DAO with Kotlin Coroutines and Flow
我正尝试在我的 Room Dao 中从 LiveData 迁移到 Flow。应用程序运行良好,但我在测试行为方面遇到问题。当我 运行 测试开始时 运行 不确定。
我也尝试使用 kotlinx.coroutines.test 运行BlockingTest,但我对 "This job has not finished yet" 有疑问,比如 here。有人可以指出正确的方向如何测试我的 CoresDao 的行为吗?
@Dao
interface CoresDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertCores(cores: List<Core>)
@Transaction
suspend fun replaceCoresData(cores: List<Core>) {
deleteAllCores()
insertCores(cores)
}
@Query("SELECT * FROM cores_table")
fun getAllCores(): Flow<List<Core>>
@Query("DELETE FROM cores_table")
suspend fun deleteAllCores()
}
@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).build()
coresDao = database.coresDao()
}
@After
fun cleanup() {
database.close()
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
@Test
fun testGetAllCores(): Unit = runBlocking {
withContext(Dispatchers.Main) {
runBlocking { coresDao.insertCores(testCoresList) }
val coresList = mutableListOf<Core>()
coresDao.getAllCores().collect { cores -> coresList.addAll(cores) }
assertThat(coresList.size, equalTo(testCoresList.size))
}
}
}
由于您已经在使用 TestCoroutineDispatcher
,因此在您的示例中使用 runBlockingTest
不会执行任何操作。
您必须 cancel
收集后 Flow
或 scope
在其中启动 Flow
编辑:可以找到此类规则的示例 here
事实证明我没有正确处理 Flow 收集和取消,这可能是问题的原因。下面是有效的代码。
可以找到更复杂的示例 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()
}
为了测试 Flow,我找到的最好的 API 是 .take(n).toList()
。您可以使用 runBlockingTest
而不需要使用 withContext
将执行移至另一个线程。
我正尝试在我的 Room Dao 中从 LiveData 迁移到 Flow。应用程序运行良好,但我在测试行为方面遇到问题。当我 运行 测试开始时 运行 不确定。 我也尝试使用 kotlinx.coroutines.test 运行BlockingTest,但我对 "This job has not finished yet" 有疑问,比如 here。有人可以指出正确的方向如何测试我的 CoresDao 的行为吗?
@Dao
interface CoresDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertCores(cores: List<Core>)
@Transaction
suspend fun replaceCoresData(cores: List<Core>) {
deleteAllCores()
insertCores(cores)
}
@Query("SELECT * FROM cores_table")
fun getAllCores(): Flow<List<Core>>
@Query("DELETE FROM cores_table")
suspend fun deleteAllCores()
}
@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).build()
coresDao = database.coresDao()
}
@After
fun cleanup() {
database.close()
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
@Test
fun testGetAllCores(): Unit = runBlocking {
withContext(Dispatchers.Main) {
runBlocking { coresDao.insertCores(testCoresList) }
val coresList = mutableListOf<Core>()
coresDao.getAllCores().collect { cores -> coresList.addAll(cores) }
assertThat(coresList.size, equalTo(testCoresList.size))
}
}
}
由于您已经在使用 TestCoroutineDispatcher
,因此在您的示例中使用 runBlockingTest
不会执行任何操作。
您必须 cancel
收集后 Flow
或 scope
在其中启动 Flow
编辑:可以找到此类规则的示例 here
事实证明我没有正确处理 Flow 收集和取消,这可能是问题的原因。下面是有效的代码。 可以找到更复杂的示例 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()
}
为了测试 Flow,我找到的最好的 API 是 .take(n).toList()
。您可以使用 runBlockingTest
而不需要使用 withContext
将执行移至另一个线程。