11

我正在尝试测试一个简单ViewModelRobolectric.

这是我的ViewModel

GreetingsViewModel.kt

@FlowPreview
@ExperimentalCoroutinesApi
class GreetingsViewModel : ViewModel() {


    private val greetingsChannel = ConflatedBroadcastChannel<String>()

    /**
     * Whenever greetingsChannel offers a value, prepend `Hello ` with it and return.
     */
    val greetingsResponse = greetingsChannel.asFlow()
        .flatMapLatest { name ->
            flowOf("Helo $name")
        }.asLiveData(viewModelScope.coroutineContext)

    /**
     * To get new greetings
     */
    fun askGreetings(name: String) {
        greetingsChannel.offer(name)
    }
}

这是我的单元测试文件

GreetingsViewModelTest.kt

@FlowPreview
@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
class GreetingsViewModelTest2 {

    @Test
    fun greeting_askGreetings_getWithName() {
        val testViewModel = GreetingsViewModel()
        testViewModel.askGreetings("john")
        testViewModel.greetingsResponse.getOrAwaitValue().should.equal("Hello john")
    }
}

但是,当我运行测试时,我遇到了错误。

java.lang.IllegalStateException: Cancel call cannot happen without a maybeRun

    at androidx.lifecycle.BlockRunner.cancel(CoroutineLiveData.kt:184)
    at androidx.lifecycle.CoroutineLiveData.onInactive(CoroutineLiveData.kt:245)
    at androidx.lifecycle.LiveData$ObserverWrapper.activeStateChanged(LiveData.java:440)
    at androidx.lifecycle.LiveData.observeForever(LiveData.java:232)
    at com.theapache64.twinkill.test.GetOrAwaitValueKt.getOrAwaitValue(getOrAwaitValue.kt:26)
    at com.theapache64.twinkill.test.GetOrAwaitValueKt.getOrAwaitValue$default(getOrAwaitValue.kt:15)
    at com.theapache64.tracktor.ui.activities.test.GreetingsViewModelTest.greeting_askGreetings_getWithName(GreetingsViewModelTest.kt:23)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.robolectric.RobolectricTestRunner$HelperTestRunner$1.evaluate(RobolectricTestRunner.java:546)
    at org.robolectric.internal.SandboxTestRunner$2.lambda$evaluate$0(SandboxTestRunner.java:252)
    at org.robolectric.internal.bytecode.Sandbox.lambda$runOnMainThread$0(Sandbox.java:89)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

知道为什么吗?

注意:getOrAwaitValue()是一个扩展函数,用于获取 a 的值LiveData或等待它有一个值,并带有超时。

4

3 回答 3

3

这是 LiveData 库中的错误,应该在 2.3.0 版本中修复

您可以在版本 2.3.0-alpha05 中测试此修复。

更改日志和问题跟踪器中的更多详细信息

https://developer.android.com/jetpack/androidx/releases/lifecycle#2.3.0-alpha05 https://issuetracker.google.com/issues/157840298

于 2020-07-21T08:05:01.233 回答
3

我面临着同样的问题。正如@Rahul Singhal 指出错误的原因是这一行

    this@getOrAwaitValue.removeObserver(this)

所以我决定将 LiveData 转换回流,然后获取值。这是我现在用来获取价值的扩展。

    suspend fun <T> LiveData<T>.getFlowAsLiveDataValue(timeMillis: Long = 2_000): T? =
        withTimeoutOrNull(timeMillis) {
        this@getFlowAsLiveDataValue.asFlow().first()
    }

你的测试应该看起来像

    testViewModel.greetingsResponse.getFlowAsLiveDataValue().should.equal("Hello john")
于 2020-05-09T19:19:49.567 回答
0

试试下面的代码

class GreetingsViewModelTest {

@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()


@Test
fun greeting_askGreetings_getWithName() {
    kotlinx.coroutines.Dispatchers.setMain(TestCoroutineDispatcher())
    val testViewModel = GreetingsViewModel()
    testViewModel.askGreetings("john")
    var name: String? = null
    testViewModel.greetingsResponse.observeForever {
        name = it
    }
    assertEquals("Helo john", name)
}

}

或删除this@getOrAwaitValue.removeObserver(this)

两种方式都可以

`

于 2020-05-01T12:12:12.803 回答