Android 在“runBlockingTest”中测试文件室的事务查询`
如何测试房间的Android 在“runBlockingTest”中测试文件室的事务查询`,android,unit-testing,testing,android-room,kotlin-coroutines,Android,Unit Testing,Testing,Android Room,Kotlin Coroutines,如何测试房间的事务数据库操作,插入设备 错误 java.lang.IllegalStateException:此作业尚未完成 在 kotlinx.coroutines.JobSupport.getCompletionExceptionOrNull(JobSupport.kt:1188) 在 kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:53) 在 kotlinx.coroutines.test.Tes
事务
数据库操作,插入设备
错误
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.andigeky.skyscannertest.db.巡回DAOTest.test插入
带腿的行程(行程DAOTEST.kt:44)在
sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法)位于
invoke(NativeMethodAccessorImpl.java:62)
行程道
@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>>
}
@Dao
@开放式测试
接口行程DAO{
@插入(onConflict=OnConflictStrategy.REPLACE)
suspend fun insertLegEntities(腿:列表)
@插入(onConflict=OnConflictStrategy.REPLACE)
suspend fun InsertiEntities(行程:列表)
@插入(onConflict=OnConflictStrategy.REPLACE)
suspend fun InsertionerAryleg(行程实体:列表)
@交易
悬吊式插入器(
行程:名单,,
腿:列表,
行程安排:列表
){
InsertIneraryEntities(行程)
insertLegEntities(腿)
插入序列(巡回序列)
}
@交易
@查询(“从行程实体中选择*)
fun GetTrainerayWithLegs():LiveData
}
行程测试
@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()
}
}
@experimentalRoutinesAPI
@RunWith(RobolectrictTestRunner::类)
@配置(sdk=[Build.VERSION\u CODES.P])
类TrainerDaoTest:DbTest(){
@获取:规则
var instantTaskExecutorRule=instantTaskExecutorRule()
@俘虏
lateinit变量捕获器:ArgumentCaptor
@以前
趣味设置(){
initMocks(this)
}
@试验
趣味`带腿测试插入行程'(){
运行阻塞测试{
val observer=mock()
val legs=TestUtil.createLegs(1)
val行程=TestUtil.createInvestineries(1)
val inventurelegs=TestUtil.createInventurelegenties(1)
skyScannerDatabase.InventureDao().InsertIneraries(行程、行程、行程表)
skyScannerDatabase.CinerayDao().GetCinerayWithLegs().ObserveForver(观察者)
船长,快跑{
验证(观察者,次数(1)).onChanged(捕获())
assertEquals(行程表大小、值大小)
}
}
}
}
DbTest
@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()
}
}
@UseExperimental(实验路线SAPI::类)
抽象类DbTest:CoroutineTestBase(){
@统治
@JvmField
val countingTaskExecutorRule=countingTaskExecutorRule()
lateinit var skyScannerDatabase:skyScannerDatabase
@以前
fun initDb(){
val app=ApplicationProvider.getApplicationContext()
skyScannerDatabase=Room.inMemoryDatabaseBuilder(应用程序,skyScannerDatabase::class.java)
.allowMainThreadQueries()
.setTransactionExecutor(Executors.newSingleThreadExecutor())
.build()
}
@之后
(b){
计数taskexecutorrule.drainTasks(10,时间单位。秒)
skyScannerDatabase.close()
}
}
您应该在测试类的顶部使用@RunWith(AndroidJUnit4::class)注释来测试DAO。作为检测测试运行(测试androidTest文件夹下的类)
看看。您应该在测试类的顶部使用@RunWith(AndroidJUnit4::class)注释来测试DAO。作为检测测试运行(测试androidTest文件夹下的类)
看看。出于好奇,为什么这是一个机器人分子测试而不是浓缩咖啡测试?以
单元测试的形式运行它
!:从正面考虑,我通常将db测试视为设备测试。为此,您可以使用默认情况下由Espresso
监控的AsyncTask.THREAD\u POOL\u EXECUTOR
。我认为您看到的问题来自setTransactionExecutor(Executors.newSingleThreadExecutor())
。使用浓缩咖啡,这种方法避免了使用IdlingResource
@Emmanuel让我试试!谢谢:)该错误实质上意味着子协同程序是在另一个作用域中启动的,并且在运行BlockingTest时它还没有完成。在构建房间数据库时,将查询执行器设置为测试协同程序调度器val dispatcher=TestCoroutineDispatcher()
然后在DB init代码中,setQueryExecutor(dispatcher.asExecutor())
。大多数测试都能很好地处理这个问题,但我目前遇到了一个事务死锁的问题。出于好奇,请看,为什么这是一个机器人分子测试而不是浓缩咖啡测试?将其作为单元测试运行!:从正面考虑,我通常将db测试视为设备测试。为此,您可以使用默认情况下由Espresso
监控的AsyncTask.THREAD\u POOL\u EXECUTOR
。我认为您看到的问题来自setTransactionExecutor(Executors.newSingleThreadExecutor())
。使用浓缩咖啡,这种方法避免了使用IdlingResource
@Emmanuel让我试试!谢谢:)该错误实质上意味着子协同程序是在另一个作用域中启动的,并且在运行BlockingTest时它还没有完成。在构建房间数据库时,将查询执行器设置为测试协同程序调度器val dispatcher=TestCoroutineDispatcher()
然后在DB init代码中,setQueryExecutor(dispatcher.asExecutor())
。大多数测试都能很好地处理这个问题,但我目前遇到了一个事务死锁的问题。看见