LiveData单元测试不会在协程和多线程下通过,因为返回true而不是预期的false

EnrollmentViewModelTest

@Test
fun getUserProfile() {
    val responsesnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
    val user = Gson().fromJson<User>(responsesnapshot,User::class.java)
    val response = Response.success(user)
    val deferred = CompletableDeferred<Response<User>>(response)

    coEvery { userService.getUserDetail() } returns deferred

    viewModel.getUserProfile()

    assert(viewModel.loadingStatus.value != null)
    assert(!UITestUtil.getvalue(viewModel.loadingStatus)!!)
    assertEquals(false,viewModel.loadingStatus.value!!)
}

这是EnrollmentViewModel.kt

fun getUserProfile() {
    loadingStatus.postvalue(true)
    job = launch {
        callAsync {
            userService.getUserDetail()
        }.onSuccess { user ->
            if (user != null) {
                processUserDetails(user)
            }
            loadingStatus.postvalue(false)
        }.onError {
            //
        }.onException {
            //
        }
    }
}

当我调试测试用例时,它表明UITestUtil.getvalue(viewModel.loadingStatus)!!是错误的。

但是很奇怪,测试用例没有通过,当我打印UITestUtil.getvalue(viewModel.loadingStatus)!!时。是真的。

它可能与loadingStatus.postvalue(true)

有关

删除后,打印结果为假。

但是我不知道为什么。

object UITestUtil {
    /**
     * Gets the value of a LiveData safely.
     */
    @Throws(InterruptedException::class)
    fun <T> getvalue(liveData: LiveData<T>): T? {
        var data: T? = null
        val latch = CountDownLatch(1)
        val observer = object : Observer<T> {
            override fun onChanged(o: T?) {
                data = o
                latch.countDown()
                liveData.removeObserver(this)
            }
        }
        liveData.observeForever(observer)
        latch.await(2,TimeUnit.SECONDS)

        return data
    }

}

已更新:

import com.google.gson.Gson
import kotlinx.coroutines.Deferred
import retrofit2.Response
import retrofit2.Response.success

data class VPlusResult<T : Any?>(
        val response: Response<T>? = null,val exception: Exception? = null
)

inline fun <T : Any> VPlusResult<T>.onSuccess(action: (T?) -> Unit): VPlusResult<T> {
    if (response?.isSuccessful == true)
        action(response.body())

    return this
}

inline fun <T : Any> VPlusResult<T>.onRawSuccess(action: (response: Response<T>) -> Unit): VPlusResult<T> {
    if (response?.isSuccessful == true)
        action(response)

    return this
}

inline fun <T : Any,TR : Any> VPlusResult<T>.map(action: (T?) -> (TR)) =
        if (response?.isSuccessful == true) VPlusResult(success(action(response.body())))
        else this as VPlusResult<TR>

inline fun <T : Any> VPlusResult<T>.onError(action: (String) -> Unit): VPlusResult<T> {
    if (response?.isSuccessful != true) {
        response?.errorBody()?.let {
            action(it.string())
        }
    }

    return this
}

inline fun <T : Any,reified G : Any> VPlusResult<T>.onErrorJson(action: (G) -> Unit): VPlusResult<T> {
    if (response?.isSuccessful != true) {
        response?.errorBody()?.let {
            action(Gson().fromJson(it.string(),G::class.java))
        }
    }

    return this
}

inline fun <T : Any> VPlusResult<T>.onRawError(action: (Response<T>?) -> Unit): VPlusResult<T> {
    if (response?.isSuccessful != true) {
        action(response)
    }

    return this
}

inline fun <T : Any?> VPlusResult<T>.onException(action: (Exception) -> Unit) {
    exception?.let { action(it) }
}

inline fun <T : Any> VPlusResult<T>.onSadness(action: (String?) -> Unit): VPlusResult<T> {
    onError {
        action(it)
    }.onException {
        action(it.message)
    }

    return this
}

suspend fun <T : Any> callAsync(block: () -> Deferred<Response<T>>): VPlusResult<T> {
    return try {
        VPlusResult(block().await())
    } catch (e: Exception) {
        VPlusResult(exception = e)
    }
}

更新2:

在assert语句之前添加以下任一语句将获得false值,该值将通过测试用例。

coVerify { userService.getUserDetail() }
coVerify { viewModel.processUserDetails(user) }

更新3: 有趣的loadAllTask​​sFromRepository_loadingTogglesAndDataLoaded() 在https://github.com/android/architecture-samples中 也可以,但是我尝试将代码引入我的代码,但是也失败了。

    @ExperimentalCoroutinesApi
    @Test
    fun getUserProfile4Using() {
        // using TestCoroutinescope in kotlinx.coroutines.test
        // Pause dispatcher so we can verify initial values
        mainCoroutineRule.pauseDispatcher()

        val responsesnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
        val user = Gson().fromJson<User>(responsesnapshot,User::class.java)
        val response = Response.success(user)
        val deferred = CompletableDeferred<Response<User>>(response)

//        coEvery { userService.getUserDetail() } returns deferred

        viewModel.getUserProfile()

        assert(viewModel.loadingStatus.value != null)

//        verify { viewModel.processUserDetails(user) }
        print(viewModel.loadingStatus.value)
        assert(UITestUtil.getvalue(viewModel.loadingStatus)!!)
        assertEquals(true,viewModel.loadingStatus.value!!)


        // Execute pending coroutines actions
        mainCoroutineRule.resumeDispatcher()

        print(viewModel.loadingStatus.value!!)
        assert(!UITestUtil.getvalue(viewModel.loadingStatus)!!)
        assertEquals(false,viewModel.loadingStatus.value!!)
    }
norika1117 回答:LiveData单元测试不会在协程和多线程下通过,因为返回true而不是预期的false

我想你可能应该使用runBlockingTesthttps://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-test/

重写测试。
fun getUserProfile() = runBlockingTest{
    val responseSnapshot = this.javaClass.getResource("/userDetailResponse.json").readText()
    val user = Gson().fromJson<User>(responseSnapshot,User::class.java)
    val response = Response.success(user)
    val deferred = CompletableDeferred<Response<User>>(response)

    coEvery { userService.getUserDetail() } returns deferred

    viewModel.getUserProfile()

    assert(viewModel.loadingStatus.value != null)
    assert(!UITestUtil.getValue(viewModel.loadingStatus)!!)
    assertEquals(false,viewModel.loadingStatus.value!!)
}

您将不必使用这些countdownlatches等。此方法从字面上解决了我在测试协程时遇到的所有问题,希望它也能对您有所帮助:)!如果没有,请告诉我。

本文链接:https://www.f2er.com/3167893.html

大家都在问