在单元测试中无法从“ Transformations.map”访问值

时间:2019-05-29 13:53:16

标签: android kotlin android-architecture-components android-livedata

要对此问题提供一些背景知识,我有一个ViewModel,它等待一些数据,将其发布到MutableLiveData,然后通过某些属性公开所有值。这是一个简短的概要:

class QuestionViewModel {

    private val state = MutableLiveData<QuestionState>()

    private val currentQuestion: Question?
        get() = (state.value as? QuestionState.Loaded)?.question

    val questionTitle: String
        get() = currentQuestion?.title.orEmpty()

    ...
}

然后,在我的测试中,我模拟数据并仅运行assertEquals检查:

assertEquals("TestTitle", viewModel.questionTitle)

到目前为止,所有这些方法都可以正常工作,但是我实际上希望我的片段在当前问题发生变化时进行观察。因此,我尝试将其更改为使用Transformations.map

class QuestionViewModel {

    private val state = MutableLiveData<QuestionState>()

    private val currentQuestion: LiveData<Question> = Transformations.map(state) {
        (it as? QuestionState.Loaded)?.question
    }

    val questionTitle: String
        get() = currentQuestion.value?.title.orEmpty()

    ...
}

突然,我在测试类中的所有断言都失败了。我公开了currentQuestion,并在我的单元测试中验证了它的值为null。我确定这是问题所在,因为:

  • 我可以模拟数据,但仍然可以从我的state LiveData中获取正确的值
  • 我可以运行我的应用程序,并在屏幕上看到预期的数据,所以这个问题是我的单元测试所特有的。

我已经将InstantTaskExecutorRule添加到了单元测试中,但是也许不能处理Transformations方法?

3 个答案:

答案 0 :(得分:1)

我最近遇到了同样的问题,我通过向LiveData添加模拟的观察者来解决了这个问题:

 @Mock
 private lateinit var observer: Observer<Question>

 init {
    initMocks(this)
 }

 fun `test using mocked observer`() {

    viewModel.currentQuestion.observeForever(observer)

    // ***************** Access currentQuestion.value here *****************

    viewModel.questionTitle.removeObserver(observer)
 }

fun `test using empty observer`() {

    viewModel.currentQuestion.observeForever {}

    // ***************** Access currentQuestion.value here *****************
 }

不确定其工作原理,或者不确定测试后不删除空观察者的后果。

此外,请确保导入正确的Observer类。如果您使用的是AndroidX:

import androidx.lifecycle.Observer

答案 1 :(得分:0)

好像您在it变量上缺少.value

private val currentQuestion: LiveData<Question> = Transformations.map(state) {
        (it.value as? QuestionState.Loaded)?.question
    }

答案 2 :(得分:0)

Luciano是正确的,这是因为未观察到LiveData。这是一个Kotlin实用程序类,可以帮助您解决这个问题。

class LiveDataObserver<T>(private val liveData: LiveData<T>): Closeable {
    private val observer: Observer<T> = mock()
    init {
        liveData.observeForever(observer)
    }
    override fun close() {
        liveData.removeObserver(observer)
    }
}

// to use:
LiveDataObserver(unit.someLiveData).use {
    assertFalse(unit.someLiveData.value!!)
}