gpt4 book ai didi

android - 使用 LiveData、协程和事务测试 Android Room

转载 作者:太空狗 更新时间:2023-10-29 14:35:26 27 4
gpt4 key购买 nike

我想测试我的数据库层,但我遇到了 22 条军规的情况。

测试用例由两部分组成:

  • 保存一些实体
  • 加载实体并断言数据库映射按预期工作

简而言之,问题在于:

  • Insert是一个suspend方法,也就是说需要在runBlocking{}
  • 中运行
  • Query 返回一个结果的 LiveData,也是异步的。因此需要观察。有 this SO 问题解释了如何做到这一点。
  • 但是,为了根据上面的链接观察 LiveData,我必须使用 InstantTaskExecutorRule。 (否则我得到 java.lang.IllegalStateException: Cannot invoke observeForever on a background thread.)
  • 这适用于大多数情况,但不适用于 @Transaction 注释的 DAO 方法。测试永远不会完成。我认为它在等待某个事务线程时陷入僵局。
  • 删除 InstantTaskExecutorRule 让 Transaction-Insert 方法完成,但我无法断言其结果,因为我需要规则才能观察数据。

详细说明

我的 Dao 类如下所示:

@Dao
interface GameDao {
@Query("SELECT * FROM game")
fun getAll(): LiveData<List<Game>>

@Insert
suspend fun insert(game: Game): Long

@Insert
suspend fun insertRound(round: RoundRoom)

@Transaction
suspend fun insertGameAndRounds(game: Game, rounds: List<RoundRoom>) {
val gameId = insert(game)
rounds.onEach {
it.gameId = gameId
}

rounds.forEach {
insertRound(it)
}
}

测试用例是:

@RunWith(AndroidJUnit4::class)
class RoomTest {
private lateinit var gameDao: GameDao
private lateinit var db: AppDatabase

@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()

@Before
fun createDb() {
val context = ApplicationProvider.getApplicationContext<Context>()
db = Room.inMemoryDatabaseBuilder(
context, AppDatabase::class.java
).build()
gameDao = db.gameDao()
}

@Test
@Throws(Exception::class)
fun storeAndReadGame() {
val game = Game(...)

runBlocking {
gameDao.insert(game)
}

val allGames = gameDao.getAll()

// the .getValueBlocking cannot be run on the background thread - needs the InstantTaskExecutorRule
val result = allGames.getValueBlocking() ?: throw InvalidObjectException("null returned as games")

// some assertions about the result here
}

@Test
fun storeAndReadGameLinkedWithRound() {
val game = Game(...)

val rounds = listOf(
Round(...),
Round(...),
Round(...)
)

runBlocking {
// This is where the execution freezes when InstantTaskExecutorRule is used
gameDao.insertGameAndRounds(game, rounds)
}

// retrieve the data, assert on it, etc
}
}

getValueBlockingLiveData 的扩展函数,几乎是从上面的链接复制粘贴的

fun <T> LiveData<T>.getValueBlocking(): T? {
var value: T? = null
val latch = CountDownLatch(1)

val observer = Observer<T> { t ->
value = t
latch.countDown()
}

observeForever(observer)

latch.await(2, TimeUnit.SECONDS)
return value
}

测试此场景的正确方法是什么?在开发数据库映射层时,我需要进行这些类型的测试,以确保一切都按我的预期进行。

最佳答案

这个问题现在有一个解决方案,在 this answer 中解释。 .

修复是向 Room 内存数据库构建器添加一行:

db = Room
.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.setTransactionExecutor(Executors.newSingleThreadExecutor()) // <-- this makes all the difference
.build()

使用单线程执行器,测试按预期工作。

关于android - 使用 LiveData、协程和事务测试 Android Room,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57027850/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com