如何解决单元测试室 android - 这项工作尚未完成
我目前正在对使用 Room 的本地数据源进行单元测试。 我创建了一个测试类:
/**
* Integration test for the [WatchListLocalDataSource].
*/
@RunWith(AndroidJUnit4::class)
@MediumTest
class WatchListLocalDataSourceTest {
private lateinit var sut: WatchListLocalDataSourceImpl
private lateinit var database: ShowsDatabase
private lateinit var entityMapper: ShowEntityMapper
private lateinit var testdispatcher: TestCoroutinedispatcher
private lateinit var testScope: TestCoroutinescope
@Before
fun setup() {
entityMapper = ShowEntityMapper()
testdispatcher = TestCoroutinedispatcher()
testScope = TestCoroutinescope(testdispatcher)
val context = InstrumentationRegistry.getInstrumentation().context
// using an in-memory database for testing,since it doesn't survive killing the process
database = Room.inMemoryDatabaseBuilder(
context,ShowsDatabase::class.java
)
.setTransactionExecutor(testdispatcher.asExecutor())
.setQueryExecutor(testdispatcher.asExecutor())
.build()
sut = WatchListLocalDataSourceImpl(database.watchListDao(),entityMapper)
}
@After
@Throws(IOException::class)
fun cleanUp() {
database.close()
}
@Test
@Throws(Exception::class)
fun observeWatchedShows_returnFlowOfDomainModel() = testScope.runBlockingTest {
val showId = 1
sut.addToWatchList(mockShow(showId))
val watchedShows: List<Show> = sut.observeWatchedShows().first()
assertthat("Watched shows should contain one element",watchedShows.size == 1)
assertthat("Watched shows element should be ${mockShow(showId).name}",watchedShows.first() == mockShow(showId))
}
}
但是,测试未完成,请注意:
java.lang.IllegalStateException: This job has not completed yet
sut
中的实际方法是:
override suspend fun addToWatchList(show: Show) = withContext(dispachers.IO) {
watchListDao.insertShow(WatchedShow(entityMapper.mapFromDomainModel(show)))
}
解决方法
所以问题始于数据源中的 addToWatchList
方法,我明确将其与 Dipachers.IO 协程范围不同,这是不必要的,因为如果您使用 suspend
函数的关键字。
这产生了一个问题,即在测试协程作用域上开始的工作正在生成一个新作用域,并且由于空间需要在它启动的同一个线程上完成,因此出现了一个导致 java.lang.IllegalStateException: This job has not completed yet
错误的死锁。
解决方案是:
- 删除 DAO 插入方法中的
withContext
,让 Room 自己处理范围。 - 在测试类的@Before 方法中将
.allowMainThreadQueries()
添加到数据库构建器,这为提供的测试范围提供了工作空间,并确保所有工作都在该定义的范围内进行。
正确的代码是:
@Before
fun setup() {
entityMapper = ShowEntityMapper()
testDispatcher = TestCoroutineDispatcher()
testScope = TestCoroutineScope(testDispatcher)
val context = InstrumentationRegistry.getInstrumentation().context
// using an in-memory database for testing,since it doesn't survive killing the process
database = Room.inMemoryDatabaseBuilder(
context,ShowsDatabase::class.java
)
.setTransactionExecutor(testDispatcher.asExecutor())
.setQueryExecutor(testDispatcher.asExecutor())
// Added this to the builder
|
v
.allowMainThreadQueries()
.build()
sut = WatchListLocalDataSourceImpl(database.watchListDao(),entityMapper)
}
在 dataSource 类中:
override suspend fun addToWatchList(show: Show) {
watchListDao.insertShow(WatchedShow(entityMapper.mapFromDomainModel(show)))
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。