Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unit testing LiveData单元测试在协程和多线程下无法通过,因为返回true而不是预期的false_Unit Testing_Kotlin_Android Architecture Components_Android Livedata_Coroutine - Fatal编程技术网

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

Unit testing LiveData单元测试在协程和多线程下无法通过,因为返回true而不是预期的false,unit-testing,kotlin,android-architecture-components,android-livedata,coroutine,Unit Testing,Kotlin,Android Architecture Components,Android Livedata,Coroutine,EnrollmentViewModelTest @Test fun getUserProfile() { val responseSnapshot = this.javaClass.getResource("/userDetailResponse.json").readText() val user = Gson().fromJson<User>(responseSnapshot, User::class.java) val response = Respon

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!!)
}
当我调试测试用例时,它显示UITestUtil.getValue(viewModel.loadingStatus)!!这是错误的

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

它可能与加载status.postValue(true)

删除后,打印结果为false

但我不知道为什么

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
    }

}
更新3: fun loadAllTasksFromRepository\u LoadingLogles和DataLoaded() 在里面 同样有效,但我尝试在代码中引入,它也失败了

    @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!!)
    }
@experimentalRoutinesAPI
@试验
fun getUserProfile4Using(){
//在kotlinx.coroutines.test中使用TestCoroutineScope
//暂停调度程序,以便我们可以验证初始值
mainCoroutineRule.pauseDispatcher()
val responseSnapshot=this.javaClass.getResource(“/userDetailResponse.json”).readText()
val user=Gson().fromJson(responseSnapshot,user::class.java)
val response=response.success(用户)
val deferred=CompletableDeferred(响应)
//coEvery{userService.getUserDetail()}返回延迟的
viewModel.getUserProfile()
断言(viewModel.loadingStatus.value!=null)
//验证{viewModel.processUserDetails(用户)}
打印(viewModel.loadingStatus.value)
断言(UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(true,viewModel.loadingStatus.value!!)
//执行挂起的协同路由操作
mainCoroutineRule.resumeDispatcher()文件
打印(viewModel.loadingStatus.value!!)
断言(!UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(false,viewModel.loadingStatus.value!!)
}

我认为您可能应该使用
运行blockingtest来重写您的测试

fun getUserProfile()=运行blockingtest{
val responseSnapshot=this.javaClass.getResource(“/userDetailResponse.json”).readText()
val user=Gson().fromJson(responseSnapshot,user::class.java)
val response=response.success(用户)
val deferred=CompletableDeferred(响应)
coEvery{userService.getUserDetail()}返回延迟的
viewModel.getUserProfile()
断言(viewModel.loadingStatus.value!=null)
断言(!UITestUtil.getValue(viewModel.loadingStatus)!!)
assertEquals(false,viewModel.loadingStatus.value!!)
}

您不必使用那些倒计时锁等。这种方法实际上解决了我在测试协同程序时遇到的所有问题,希望它也能帮助您:)!如果没有,请告诉我。

谢谢您的回答。我粘贴了你的代码并进行了测试,但仍然失败。调试时,UITestUtil.getValue(viewModel.loadingStatus)!!仍然返回false。但奇怪的是,它仍然未能通过测试。你需要提供更多的代码-你的callAsync ext函数做什么?更新了它。似乎coEvery正在挂起其余语句:if(user!=null){processUserDetails(user)}loadingStatus.postValue(false)
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)
    }
}
coVerify { userService.getUserDetail() }
coVerify { viewModel.processUserDetails(user) }
    @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!!)
    }
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!!)
}