【问题标题】:Unable to access value from `Transformations.map` in unit test无法在单元测试中访问“Transformations.map”中的值
【发布时间】:2019-05-29 13:53:16
【问题描述】:

为了给这个问题一些背景知识,我有一个 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,并在我的单元测试中验证了它的值为空。我确定这是问题所在,因为:

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

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

【问题讨论】:

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


    【解决方案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
    

    【讨论】:

    • 它之所以有效,是因为没有观察者就无法进行转换。当您在视图中引用 LiveData 属性时,您通常会观察它,如果您使用数据绑定,那么观察它的代码就是为您编写的。
    【解决方案2】:

    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!!)
    }
    

    【讨论】:

      【解决方案3】:

      看起来您缺少 it 变量上的 .value

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

      【讨论】:

        猜你喜欢
        • 2021-09-24
        • 1970-01-01
        • 1970-01-01
        • 2018-05-18
        • 1970-01-01
        • 2023-04-06
        • 1970-01-01
        • 2014-08-21
        • 1970-01-01
        相关资源
        最近更新 更多