不模拟LiveData android.os.Looper的单元测试

tyc*_*czj 5 android unit-testing mockito android-livedata android-architecture-components

我正在尝试对通过将一些内容发布回活动的ViewModel进行单元测试,LiveData但是当我运行设置livedata值的方法时,出现了错误

java.lang.RuntimeException:android.os.Looper中的方法getMainLooper没有被模拟。

我已经阅读了几篇文章和文章,您所要做的就是添加Rulefor InstantTaskExecutorRule,它应该可以正常工作,但是我做到了,但仍然出现错误。

这是我的单元测试

    val observer: Observer<String> = mock(Observer::class.java) as Observer<String>

    @get:Rule
    var rule: TestRule = InstantTaskExecutorRule()

    @Test
    fun testSearchDataValidationFailureMissingSearchLocation() {
        val viewModel = MoveViewModel()

        val param1= 0
        val param2= 1
        val param3= "1234"
        viewModel.dialogMessageLiveData.observeForever(observer)

        Assert.assertFalse(viewModel.validateSearchData(param1, param2, param3))

        verify(observer).onChanged("Data not valid")
    }
Run Code Online (Sandbox Code Playgroud)

这是我要测试的方法

fun validateSearchData(param1:Int,param2:Int,param3:String):Boolean{
        var valid:Boolean = false

        if(param1== 0 || param2== 0 || param3.isBlank()){
            dialogMessageLiveData.postValue("Data not valid")
        }else{
            valid = true
        }

        return valid
    }
Run Code Online (Sandbox Code Playgroud)

我不确定该如何解决,有人可以建议其他解决方案吗?

小智 2

您可以使用此扩展来获取 [LiveData] 的值,或者等待它获得一个超时值。在主机端 (JVM) 测试中使用此扩展。建议与它一起使用InstantTaskExecutorRule或类似的机制来同步执行任务。

@VisibleForTesting(otherwise = VisibleForTesting.NONE)
fun <T> LiveData<T>.getOrAwaitValue(
    time: Long = 2,
    timeUnit: TimeUnit = TimeUnit.SECONDS,
    afterObserve: () -> Unit = {}
): T {
    var data: T? = null
    val latch = CountDownLatch(1)
    val observer = object : Observer<T> {
        override fun onChanged(o: T?) {
            data = o
            latch.countDown()
            this@getOrAwaitValue.removeObserver(this)
        }
    }
    this.observeForever(observer)

    try {
        afterObserve.invoke()

        // Don't wait indefinitely if the LiveData is not set.
        if (!latch.await(time, timeUnit)) {
            throw TimeoutException("LiveData value was never set.")
        }

    } finally {
        this.removeObserver(observer)
    }

    @Suppress("UNCHECKED_CAST")
    return data as T
}
Run Code Online (Sandbox Code Playgroud)

然后在你的测试用例中你可以获得值

viewModel.dialogMessageLiveData.getOrAwaitValue() 
Run Code Online (Sandbox Code Playgroud)