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())
。大多数测试都能很好地处理这个问题,但我目前遇到了一个事务死锁的问题。看见