android - 在 `runBlockingTest` 中测试 Room 的事务查询
问题描述
如何测试Room 的Transaction
数据库操作?insertItineraries
错误
java.lang.IllegalStateException:此作业尚未完成
在 kotlinx.coroutines.JobSupport.getCompletionExceptionOrNull(JobSupport.kt:1188) 在 kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:53) 在 kotlinx.coroutines.test.TestBuildersKt.runBlockingTest$default(TestBuilders.kt:45 ) 在 com.andigeeky.skyscannertest.db.ItineraryDaoTest.test 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 处插入行程 (ItineraryDaoTest.kt:44) )
行程道
@Dao
@OpenForTesting
interface ItineraryDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertLegEntities(legs: List<LegEntity>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertItineraryEntities(itineraries: List<ItineraryEntity>)
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertItineraryLeg(itineraryLegEntities: List<ItineraryLegEntity>)
@Transaction
suspend fun insertItineraries(
itineraries: List<ItineraryEntity>,
legs: List<LegEntity>,
itineraryLegEntities: List<ItineraryLegEntity>
){
insertItineraryEntities(itineraries)
insertLegEntities(legs)
insertItineraryLeg(itineraryLegEntities)
}
@Transaction
@Query("SELECT * FROM ItineraryEntity")
fun getItineraryWithLegs(): LiveData<List<ItineraryWithLegs>>
}
行程道测试
@ExperimentalCoroutinesApi
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.P])
class ItineraryDaoTest : DbTest() {
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
@Captor
lateinit var captor: ArgumentCaptor<ArrayList<ItineraryWithLegs>>
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
}
@Test
fun `test insert itineraries with legs`() {
runBlockingTest {
val observer = mock<Observer<List<ItineraryWithLegs>>>()
val legs = TestUtil.createLegs(1)
val itineraries = TestUtil.createItineraries(1)
val itineraryLegs = TestUtil.createItineraryLegEntities(1)
skyScannerDatabase.itineraryDao().insertItineraries(itineraries, legs, itineraryLegs)
skyScannerDatabase.itineraryDao().getItineraryWithLegs().observeForever(observer)
captor.run {
verify(observer, times(1)).onChanged(capture())
assertEquals(itineraryLegs.size, value.size)
}
}
}
}
数据库测试
@UseExperimental(ExperimentalCoroutinesApi::class)
abstract class DbTest : CoroutineTestBase() {
@Rule
@JvmField
val countingTaskExecutorRule = CountingTaskExecutorRule()
lateinit var skyScannerDatabase: SkyScannerDatabase
@Before
fun initDb() {
val app = ApplicationProvider.getApplicationContext<Context>()
skyScannerDatabase = Room.inMemoryDatabaseBuilder(app, SkyScannerDatabase::class.java)
.allowMainThreadQueries()
.setTransactionExecutor(Executors.newSingleThreadExecutor())
.build()
}
@After
fun closeDb() {
countingTaskExecutorRule.drainTasks(10, TimeUnit.SECONDS)
skyScannerDatabase.close()
}
}
解决方案
您应该在测试类的顶部使用@RunWith(AndroidJUnit4::class)注释来测试您的 DAO。作为仪器测试运行(测试 androidTest 文件夹下的类)。
@RunWith(AndroidJUnit4::class)
class YourTestClass {
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
lateinit var skyScannerDatabase: SkyScannerDatabase
@Before
fun initDb() {
val app = ApplicationProvider.getApplicationContext<Context>()
skyScannerDatabase = Room.inMemoryDatabaseBuilder(app, SkyScannerDatabase::class.java)
.allowMainThreadQueries()
.setTransactionExecutor(Executors.newSingleThreadExecutor())
.build()
}
@After
fun closeDb() {
skyScannerDatabase.close()
}
// ...
@Test
fun testMethod() = runBlockingTest {
skyScannerDatabase.itineraryDao().insertItineraries(...)
}
}
你的 build.gradle 模块应该有以下配置。
android {
// ...
defaultConfig {
// ...
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// ...
}
}
// kotlin_coroutines_version = '1.3.3'
// test_arch_core_testing = '2.1.0'
// test_ext_junit_version = '1.1.1'
// test_runner_version = '1.2.0'
dependencies {
androidTestImplementation "androidx.arch.core:core-testing:$test_arch_core_testing"
androidTestImplementation "androidx.test.ext:junit:$test_ext_junit_version"
androidTestImplementation "androidx.test:runner:$test_runner_version"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlin_coroutines_version"
}
看看这篇文章。
推荐阅读
- maven - AEM 项目发布版本
- mysql - MySQL通过存储过程从带有LIMIT的更新查询中获取行数据
- maptitude - 我可以使用什么方法(Maptitude 是我的软件)来查找区域内每条道路的总里程?
- amazon-web-services - SQS fifo 触发器调用 Lambda 函数(1 条消息 - 1 次调用)
- typescript - 动作创建者文档评论未显示
- node.js - 迁移到节点 v14 后 express.js 出现语法错误,将文件更改为 mjs 类型并导入语句
- c - 我在 Arduino 网络服务器中显示浮点变量时遇到问题
- r - 在 MRO 中安装基于 Fortran 的 R 包会在链接行中显示版权信息
- c# - 无法将构建结果发送到 SonarQube 服务器
- vue.js - Vuetify 和 vue.js,改变实际按钮图标大小的最佳方法是什么?