在 Kotlin 中编写具有特征的 Android 测试时出现 java.lang.VerifyError

Posted

技术标签:

【中文标题】在 Kotlin 中编写具有特征的 Android 测试时出现 java.lang.VerifyError【英文标题】:java.lang.VerifyError when writing Android tests with traits in Kotlin 【发布时间】:2014-09-01 23:56:18 【问题描述】:

我正在尝试为 androidInstrumentationTestCase 创建一个特征,其中包含一个抽象属性和一个使用该属性的方法。不幸的是,当我运行此测试时,它会以java.lang.VerifyError 崩溃。所以这里有一个导致崩溃的代码示例:

trait ExtendedInstrumentationTestCase : InstrumentationTestCase 
    val string: String

    fun printString(): Unit 
        println(string)
    


class MyApplicationTestCase :
        ApplicationTestCase<Application>(javaClass<Application>()),
        ExtendedInstrumentationTestCase 

    override val string: String = "test"

    override fun setUp() 
        super<ApplicationTestCase>.setUp()

        printString()
    

    override fun tearDown() 
        super<ApplicationTestCase>.tearDown()
    

这就是我从 logcat 中得到的:

W/dalvikvm﹕ VFY: Lcom/kotlintest/MyApplicationTestCase; is not instance of Landroid/test/InstrumentationTestCase;
W/dalvikvm﹕ VFY: bad arg 0 (into Landroid/test/InstrumentationTestCase;)
W/dalvikvm﹕ VFY:  rejecting call to Lcom/kotlintest/ExtendedInstrumentationTestCase$$TImpl;.printString (Landroid/test/InstrumentationTestCase;)V
W/dalvikvm﹕ VFY:  rejecting opcode 0x71 at 0x0000
W/dalvikvm﹕ VFY:  rejected Lcom/kotlintest/MyApplicationTestCase;.printString ()V
W/dalvikvm﹕ Verifier rejected class Lcom/kotlintest/MyApplicationTestCase;
W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0xb1e90648)
E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.VerifyError: com/kotlintest/MyApplicationTestCase
            at java.lang.Class.getDeclaredConstructors(Native Method)
            at java.lang.Class.getConstructors(Class.java:459)
            at android.test.suitebuilder.TestGrouping$TestCasePredicate.hasValidConstructor(TestGrouping.java:228)
            at android.test.suitebuilder.TestGrouping$TestCasePredicate.apply(TestGrouping.java:217)
            at android.test.suitebuilder.TestGrouping$TestCasePredicate.apply(TestGrouping.java:213)
            at android.test.suitebuilder.TestGrouping.select(TestGrouping.java:172)
            at android.test.suitebuilder.TestGrouping.selectTestClasses(TestGrouping.java:162)
            at android.test.suitebuilder.TestGrouping.testCaseClassesInPackage(TestGrouping.java:156)
            at android.test.suitebuilder.TestGrouping.addPackagesRecursive(TestGrouping.java:117)
            at android.test.suitebuilder.TestSuiteBuilder.includePackages(TestSuiteBuilder.java:102)
            at android.test.InstrumentationTestRunner.onCreate(InstrumentationTestRunner.java:366)
            at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4435)
            at android.app.ActivityThread.access$1300(ActivityThread.java:141)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1316)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)

当我将 printString() 方法作为扩展方法时,我的测试开始工作:

trait ExtendedInstrumentationTestCase : InstrumentationTestCase 
    val string: String


fun ExtendedInstrumentationTestCase.printString(): Unit 
    println(string)

据我所知,该错误在 Dalvik 中,但我想确切地知道错误在哪里,为什么会发生以及如何更改我的特征的第一个版本以使此代码正常工作。

【问题讨论】:

这些错误已在 YouTrack 中报告为已修复。 【参考方案1】:

这是 Kotlin 编译器中的一个错误:KT-3006。

问题是你继承了一个需要类的特征,而不调用超类的构造函数。编译器错误地允许这样做,并在运行时稍后崩溃。

正确的解决方法是显式调用InstrumentationTestCase的构造函数:

class MyApplicationTestCase :
        ApplicationTestCase<Application>(javaClass<Application>()),
        ExtendedInstrumentationTestCase,
        InstrumentationTestCase() 
...

【讨论】:

谢谢!看来bug确实出在Kotlin编译器中,但问题更严重。我刚刚注意到ApplicationTestCase 不是InstrumentationTestCase 的子类,所以在这种情况下一定不允许从这个trait 继承。 我发现了这个行为的一个错误:KT-1963. 其实这两个bug是同一个,所以我把它们合并了。抱歉,如果一开始不清楚:是的,编译器不应该允许您的原始代码。每个子类都必须满足每个特征要求,但编译器目前不会检查 这些错误已在 YouTrack 中报告为已修复,因此不再是问题。

以上是关于在 Kotlin 中编写具有特征的 Android 测试时出现 java.lang.VerifyError的主要内容,如果未能解决你的问题,请参考以下文章

用 Kotlin 编写的 Android 库,提供对 Java 应用程序的支持

用 Kotlin 编写的 Android 库,提供对 Java 应用程序的支持

Kotlin - 协程基础及原理

在用 Kotlin 编写的 Android 库的公共 API 中处理 R8 + JvmStatic Annotation + Lambda

如何从 Firebase android kotlin 获取所有具有特定价值的孩子?

使用 Kotlin 重写 AOSP 日历应用