android 如何在单元测试期间使用Debug工具查找ClassCastException?

von4xj4u  于 2023-04-18  发布在  Android
关注(0)|答案(1)|浏览(79)

我在单元测试时得到了这个错误。

class com.example.model.common.shop.manager_cart.CartInfo cannot be cast to class kotlin.Result (com.example.model.common.shop.manager_cart.CartInfo and kotlin.Result are in unnamed module of loader 'app')
java.lang.ClassCastException: class com.example.model.common.shop.manager_cart.CartInfo cannot be cast to class kotlin.Result (com.example.model.common.shop.manager_cart.CartInfo and kotlin.Result are in unnamed module of loader 'app')
    at com.example.store.ui.feature.result.CartUiUpdateManager.updateCartUi(CartUiSyncManager.kt:30)
    at com.example.store.ui.feature.result.CartUiUpdateManager$updateCartUi$1.invokeSuspend(CartUiSyncManager.kt)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
    at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
    at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
    at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
    at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
    at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
    at kotlinx.coroutines.EventLoopImplBase$DelayedResumeTask.run(EventLoop.common.kt:500)
    at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:284)
    at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
    at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
    at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
    at com.example.store.CartUiUpdateManagerTest.sending three requests must call onWarn, move request to tempRequestQueue, process and call onSuccess(CartUiUpdateManagerTest.kt:43)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at jdk.proxy1/jdk.proxy1.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:176)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
    at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:133)
    at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:71)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
    at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

and `updateCartUi(CartUiSyncManager.kt:30)` is `val result = request.invoke()`

下面是CartUiUpdateManager类。

class CartUiUpdateManager {
    private var lastRequestHashCode = 0
    val requestQueue: MutableList<suspend () -> Result<CartInfo>> = mutableListOf()
    val tempRequestQueue: MutableList<suspend () -> Result<CartInfo>> = mutableListOf()
    private var isCalling = false
    suspend fun updateCartUi(
        newRequest: suspend () -> Result<CartInfo>,
        onSuccess: suspend (CartInfo) -> Unit,
        onFailure: suspend (Throwable) -> Unit,
        onWarn: suspend (String) -> Unit
    ) {
        if (requestQueue.size == MAX_REQUEST) {
            onWarn.invoke("Too many requests. Please wait.")
            tempRequestQueue.add(newRequest)
            return
        }

        requestQueue.add(newRequest)

        while (requestQueue.isNotEmpty()) {
            isCalling = true
            val request = requestQueue.removeFirst()
            lastRequestHashCode = newRequest.hashCode()
            delay(DELAY_BETWEEN_API)

            val response: Result<CartInfo> = request.invoke()

            response.onSuccess {
                if (tempRequestQueue.isNotEmpty()) {
                    requestQueue.add(tempRequestQueue.removeFirst())
                    requestQueue.add(tempRequestQueue.removeFirst())
                } else if (requestQueue.isEmpty() && lastRequestHashCode == newRequest.hashCode()) {
                    isCalling = false
                    onSuccess.invoke(it)
                }
            }.onFailure {
                if (requestQueue.isEmpty() && tempRequestQueue.isEmpty()) {
                    isCalling = false
                }
                onFailure.invoke(it)
            }
        }
    }

    companion object {
        const val MAX_REQUEST = 2
        const val DELAY_BETWEEN_API = 70L
    }
}

下面是我的单元测试代码。

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.mockk
import com.example.model.common.shop.manager_cart.CartInfo
import com.example.store.ui.feature.result.CartUiUpdateManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class CartUiUpdateManagerTest {
    @get:Rule
    var instantExecutorRule = InstantTaskExecutorRule()

    private lateinit var cartUiUpdateManager: CartUiUpdateManager

    @Before
    fun setUp() {
        Dispatchers.setMain(Dispatchers.Unconfined)
        cartUiUpdateManager = CartUiUpdateManager()
    }

    @After
    fun tearDown() {
        Dispatchers.resetMain()
    }

    @Test
    fun `sending less than 3 request calls must call onSuccess`() = runTest {
        val mockRequest = mockk<suspend () -> Result<CartInfo>>()
        val cartInfo = mockk<CartInfo>(relaxed = true)
        coEvery { mockRequest() } returns Result.success(cartInfo)

        val onSuccess = mockk<suspend (CartInfo) -> Unit>(relaxed = true)
        val onFailure = mockk<suspend (Throwable) -> Unit>(relaxed = true)
        val onWarn = mockk<suspend (String) -> Unit>(relaxed = true)

        cartUiUpdateManager.updateCartUi(
            newRequest = mockRequest,
            onSuccess = onSuccess,
            onFailure = onFailure,
            onWarn = onWarn
        )
        cartUiUpdateManager.updateCartUi(
            newRequest = mockRequest,
            onSuccess = onSuccess,
            onFailure = onFailure,
            onWarn = onWarn
        )

        coVerify(exactly = 2) { onSuccess(cartInfo) }
        coVerify(exactly = 0) { onFailure(any()) }
        coVerify(exactly = 0) { onWarn(any()) }
    }

    @Test
    fun `sending three requests must call onWarn, move request to tempRequestQueue, process and call onSuccess`() = runBlocking {
        val mockRequest = mockk<suspend () -> Result<CartInfo>>()
        val cartInfo = mockk<CartInfo>(relaxed = true)
        val successResult = Result.success(cartInfo)

        coEvery { mockRequest() } returns successResult

        val onSuccess = mockk<suspend (CartInfo) -> Unit>(relaxed = true)
        val onFailure = mockk<suspend (Throwable) -> Unit>(relaxed = true)
        val onWarn = mockk<suspend (String) -> Unit>(relaxed = true)

        cartUiUpdateManager.updateCartUi(
            newRequest = mockRequest,
            onSuccess = onSuccess,
            onFailure = onFailure,
            onWarn = onWarn
        )
        cartUiUpdateManager.updateCartUi(
            newRequest = mockRequest,
            onSuccess = onSuccess,
            onFailure = onFailure,
            onWarn = onWarn
        )
        cartUiUpdateManager.updateCartUi(
            newRequest = mockRequest,
            onSuccess = onSuccess,
            onFailure = onFailure,
            onWarn = onWarn
        )

        coVerify(exactly = 1) { onWarn("Too many requests. Please wait.") }
        Assert.assertEquals(1, cartUiUpdateManager.tempRequestQueue.size)

        // Simulate the first two requests being processed successfully
        cartUiUpdateManager.requestQueue.clear()
        cartUiUpdateManager.tempRequestQueue.removeFirst()

        coVerify(exactly = 3) { onSuccess(cartInfo) }
        coVerify(exactly = 0) { onFailure(any()) }
    }
}

有问题的部分是val response: Result<CartInfo> = request.invoke()。我不知道为什么它需要铸造。
我如何调试和修复这个问题,使这些单元测试工作正常?

hiz5n14c

hiz5n14c1#

堆栈跟踪告诉你错误在第30行:

at com.example.store.ui.feature.result.CartUiUpdateManager.updateCartUi(CartUiSyncManager.kt:30)

你给我们看的代码中没有行号,但我想是这个:

val response: Result<CartInfo> = request.invoke()

request.invoke()返回的是CartInfo,但您需要的是Result

相关问题