【问题标题】:android Test Room + Paging 3 +Flow test has different result on each runandroid Test Room + Paging 3 +Flow测试每次运行都有不同的结果
【发布时间】:2021-06-13 10:42:58
【问题描述】:

第 3 页,带房间。 我已经创建了一个类似于示例here 的应用程序并开始为其编写测试。

这是我在 DAO 中的内容:

@Query("SELECT * FROM Model")
fun getModels(): PagingSource<Int, Model>

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(list: MutableList<Model>) : Completable

我想像这样测试它:

@OptIn(ExperimentalCoroutinesApi::class) 
class DAOTest {

    private lateinit var dao: Dao
    private lateinit var db: ModelDatabase
    private lateinit var viewModel: MyViewModel
    lateinit var context: Context
    private val testDispatcher = TestCoroutineDispatcher()

    @Before
    fun createDb() {

        Dispatchers.setMain(testDispatcher)
        context = InstrumentationRegistry.getInstrumentation().targetContext
        db = Room.inMemoryDatabaseBuilder(context, MyDatabase::class.java)
            .allowMainThreadQueries()
            .build()
        dao = db.Dao()
        viewModel =
            MyViewModel(MyRepository(db))
    }

    @After
    fun tearDown() {
        Dispatchers.resetMain()
        db.close()
    }

    @Test
    fun dataBase_insertAndGet_success() = runBlockingTest(testDispatcher) {
        val differ = AsyncPagingDataDiffer(
            MyAdapter.diffCallback,
            noopListUpdateCallback,
            testDispatcher,
            testDispatcher
        )
        dao.insertAll(
            mutableListOf(listOfModels)
        ).test().assertResult()

        val job = launch {
            viewModel.getList().collectLatest {
                differ.submitData(it)
            }
        }
        advanceUntilIdle()
        Truth.assertThat(differ.snapshot()).containsExactly(
            model1, model2,model3,model4)
        job.cancel()
    }

    private val noopListUpdateCallback = object : ListUpdateCallback {
        override fun onInserted(position: Int, count: Int) {}
        override fun onRemoved(position: Int, count: Int) {}
        override fun onMoved(fromPosition: Int, toPosition: Int) {}
        override fun onChanged(position: Int, count: Int, payload: Any?) {}
    }
}

与示例中的测试完全一样。 奇怪的是,当我多次运行测试时,有些通过了,有些则没有(说differ.snapshot()是空的) 当我在这个文件中有几个其他测试(测试更新和删除)并尝试一起运行整个测试时,也会发生这种情况,有些通过,有些不通过,每轮通过的测试都不同。

这就是我在 ViewModel 中用于获取列表的内容:

fun getList(type: Int, search: String? = null): Flow<PagingData<Stock>> {

        return Pager(
            config = PagingConfig(
                pageSize = PAGE_SIZE,
                enablePlaceholders = true,
                maxSize = MAX_SIZE
            )
        ) {
           repository.getListFromDao()
        }.flow
            .cachedIn(viewModelScope)

一切都像示例,但不知道为什么会发生这种行为。 我看到了像this 这样的其他帖子,这正是我在测试中所做的,但我仍然遇到同样的问题。 我应该提到,当我尝试在没有返回 PagingSource 类型的情况下测试如下查询时:

@Query("SELECT * FROM Model")
fun getModels(): List<Model>

一切正常。每次我运行它时测试都会通过。所以我认为测试中这部分有问题:

val job = launch {
    viewModel.getList().collectLatest {
        differ.submitData(it)
    }
}

如果有人可以提供帮助并提供一些提示,我将非常高兴,因为我已经为此工作了很长时间。 谢谢。

【问题讨论】:

  • 在为 submitData 启动作业后插入是否有帮助?由于您没有使用暂停版本,因此我不确定 Paging 是否会在比赛中及时恢复失效
  • 感谢您的评论。我做到了,没有不工作。这来自 android 文档:直接使用 PagingSource 类来使用 Kotlin 协程进行异步加载。所以它使用引擎盖下的暂停。在为differ.submitdata 提供午餐的示例中,它说:submitData 允许diff 从PagingData 接收数据,但会暂停直到失效,因此我们必须在单独的作业中启动它。想也许它有助于解决问题。不知道幕后发生了什么。
  • 正如你所说,这似乎是因为不同。正如文档所说:“注意:submitData() 方法暂停并且在 PagingSource 无效或调用适配器的 refresh 方法之前不会返回。这意味着 submitData() 调用之后的代码可能比您预期的要晚得多。”并且当我在启动后调用differ.refresh() 多次运行测试时它是可以的,但是当我一起运行所有测试时,再次通过一些不通过,但单次运行是可以的。在断言之前不知道如何强制不同给我结果。

标签: android android-room android-testing android-paging-3 kotlin-coroutines


【解决方案1】:

我相信您需要等待失效发生,这是在插入时从 Room 的末尾通过 InvalidationTracker 触发的。

Room 默认使用 ArchTaskExecutors,您可以通过 RoomDatabase Builder 覆盖它或与有用的 InstantTaskExecutorRule 同步

@get:Rule
val instantRule = InstantTaskExecutorRule()

【讨论】:

  • 哦,这似乎是一个非常合理的失败原因,但不幸的是它没有工作,仍然像以前一样。
猜你喜欢
  • 2023-01-18
  • 2011-08-07
  • 2020-12-12
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 2012-05-02
  • 2016-07-31
  • 2018-12-24
相关资源
最近更新 更多