【问题标题】:java.lang.VerifyError Precise Reference expected while trying to runBlocking Kotlin suspended fun in Androidjava.lang.VerifyError 尝试运行时需要精确参考 Blocking Kotlin 在 Android 中暂停乐趣
【发布时间】:2020-04-07 19:21:44
【问题描述】:

我正在尝试编写一个单元测试,等待完成一个 kotlin 挂起函数,然后再检查如下结果:

@Test
fun shouldSetupThingsProperly() {
    val context = InstrumentationRegistry.getInstrumentation().context
    runBlocking { MyObject.enable(context, false) }
    Assert.assertTrue( /* whatever usefull */ true)
}

暂停方法如下:

object MyObject {

    @JvmStatic
    suspend fun enable(context: Context, enable: Boolean) {
        withContext(Dispatchers.IO) {
            // ... do some work
            wakeup(context)
        }
    }

    private suspend fun wakeup(context: Context) {
        withContext(Dispatchers.IO) {
            try {
                // setup things ...
            } catch (ignore: Exception) {}
        }
    }

}

测试运行结束于:

java.lang.VerifyError: Verifier rejected class MyObject: java.lang.Object MyObject.enable(android.content.Context, boolean, kotlin.coroutines.Continuation) failed to verify: java.lang.Object MyObject.enable(android.content.Context, boolean, kotlin.coroutines.Continuation): [0x16] register v7 has type Reference: android.content.Context but expected Precise Reference: MyObject (declaration of 'MyObject' appears in /data/app/test-_rphd0tDrOp0KM-Bz09NWA==/base.apk!classes2.dex)
at MyObject.enable(Unknown Source:0)

我对协程不熟悉,我想知道如何正确地等待测试中的启用挂起功能完成,或者错误是由于其他错误引起的......

【问题讨论】:

    标签: java android kotlin kotlin-coroutines


    【解决方案1】:

    测试协程是一个技巧,即使有一些经验。 如果可以导入,这将非常有帮助:https://github.com/Kotlin/kotlinx.coroutines/tree/master/kotlinx-coroutines-test

    如果你有这个依赖测试协程变得更易于管理。

    首先,如果您可以让正在运行的调度程序成为可以设置或覆盖的变量或参数,它将帮助您提高可测试性。

    就编写测试而言,您可以执行以下操作:

    @Before
    fun before() {
        Dispatchers.setMain(mainThreadSurrogate)
    }
    
    @Test
    fun shouldSetupThingsProperly() = runBlockingTest {
        val context = InstrumentationRegistry.getInstrumentation().context
        MyObject.enable(context, false, Dispatchers.Main)
        Assert.assertTrue( /* whatever useful */ true)
    }
    

    你的对象本身会有更多的变化

    object MyObject {
    
        @JvmStatic
        suspend fun enable(context: Context, enable: Boolean, dispatcher: CoroutineDispatcher = Dispatchers.IO) {
             // If you need a return feel free to use withContext such as:
             // val result = withContext(dispatcher) { /* Return Value */ Any() }
    
            CoroutineScope(dispatcher).run {
                // ... do some work
                wakeup(context)
            }
        }
    
        private suspend fun wakeup(context: Context) {
            // Another coroutine scope is unnecessary here, it will inherit the parent scope automatically, so you can call
            // async functions here
            delay(200)
    
            try {
                // setup things ...
            } catch (exc: Exception) {
                // We had an issue
            }
        }
    }
    

    【讨论】:

    • 您在给出的代码之外调用的东西导致了错误。这不太可能是 Kotlin 错误。
    • 只是将 withContext(Dispatchers.IO) {} 替换为 CoroutineScope(Dispatchers.IO).launch {} 使 VerifierError 消失
    • VerifierError 通常与编译器问题有关...我会让 Kotlin 人调查
    • 啊,是的,这可能是测试环境中调度程序的问题,IO调度程序过去曾给我问题
    【解决方案2】:

    如果它发生在 Android 或 Flutter 上的 coroutines-withContext 上,将 coroutines lib 恢复到 1.3.6 为我解决了崩溃问题。 看来android coroutines lib 1.3.7-1.3.8版本有VerifyError bug,1.4.0后修复。

    详情见链接:

    https://github.com/Kotlin/kotlinx.coroutines/issues/2049https://github.com/Kotlin/kotlinx.coroutines/issues/2041

    【讨论】:

      猜你喜欢
      • 2018-08-14
      • 2020-01-04
      • 1970-01-01
      • 2019-05-20
      • 2020-06-24
      • 2020-04-05
      • 1970-01-01
      • 2019-11-22
      • 2019-07-23
      相关资源
      最近更新 更多