Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin JaCoCo, no coverage -> IllegalClassFormatException ... Please supply original non-instrumented classes

kotlin verion: 1.3.61

Android Gradle Plugin: 3.5.3

JaCoCo Version: 0.8.4.201905082037 (default android gradle version)

project: https://github.com/goldy1992/Mp3Player/tree/feature/issue-112/migrate-to-kotlin

I have a multi module gradle project with: 2 flavours: full, automation 2 build types: release, debug

I'm in the process of migrating everything to kotlin.

Module structure

  • commons [android library] (works as expected with test coverage)
  • client-test-support (used for test implementations of activities)
  • client [android library] (no coverage) -> depends on commons, client-test-support
  • service-test-support (used for test implementations of activities)
  • service [android library] (no coverage) -> depends on commons, service-test-support
  • app [android application] no tests

For the context of this posts, I'm only interested in unit tests

The tests run as expected however no coverage is generated due to a SOME (not all) of the kotlin compiled classes being recognised as "instrumented classes"

The errors appear just as the tests are about to being where the following is printed out for many classes:

    java.lang.instrument.IllegalClassFormatException: Error while instrumenting com/github/goldy1992/mp3player/client/views/viewholders/MediaPlayerTrackViewHolder.
        at org.jacoco.agent.rt.internal_035b120.CoverageTransformer.transform(CoverageTransformer.java:93)
        at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
        at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        at java.lang.Class.getDeclaredFields0(Native Method)
        at java.lang.Class.privateGetDeclaredFields(Class.java:2583)
        at java.lang.Class.getDeclaredFields(Class.java:1916)
        at org.junit.runners.model.TestClass.getSortedDeclaredFields(TestClass.java:77)
        at org.junit.runners.model.TestClass.scanAnnotatedMembers(TestClass.java:70)
        at org.junit.runners.model.TestClass.<init>(TestClass.java:57)
        at org.junit.runners.ParentRunner.createTestClass(ParentRunner.java:88)
        at org.junit.runners.ParentRunner.<init>(ParentRunner.java:83)
        at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:65)
        at org.robolectric.internal.SandboxTestRunner.<init>(SandboxTestRunner.java:71)
        at org.robolectric.RobolectricTestRunner.<init>(RobolectricTestRunner.java:101)
        at org.robolectric.RobolectricTestRunner.<init>(RobolectricTestRunner.java:96)
        at sun.reflect.GeneratedConstructorAccessor5.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
        at org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder$DefensiveAnnotatedBuilder.buildRunner(DefensiveAllDefaultPossibilitiesBuilder.java:113)
        at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
        at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
        at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
        at org.junit.vintage.engine.discovery.DefensiveAllDefaultPossibilitiesBuilder.runnerForClass(DefensiveAllDefaultPossibilitiesBuilder.java:56)
        at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
        at org.junit.vintage.engine.discovery.TestClassRequestResolver.createRunnerTestDescriptor(TestClassRequestResolver.java:55)
        at org.junit.vintage.engine.discovery.VintageDiscoverer.lambda$discover$0(VintageDiscoverer.java:53)
        at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
        at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
        at java.util.Iterator.forEachRemaining(Iterator.java:116)
        at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
        at java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)
        at java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:742)
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
        at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
        at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
        at org.junit.vintage.engine.discovery.VintageDiscoverer.discover(VintageDiscoverer.java:55)
        at org.junit.vintage.engine.VintageTestEngine.discover(VintageTestEngine.java:62)
        at org.junit.platform.launcher.core.DefaultLauncher.discoverEngineRoot(DefaultLauncher.java:168)
        at org.junit.platform.launcher.core.DefaultLauncher.discoverRoot(DefaultLauncher.java:155)
        at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:128)
        at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:102)
        at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:82)
        at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:78)
        at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:61)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        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 com.sun.proxy.$Proxy2.stop(Unknown Source)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.stop(TestWorker.java:132)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
        at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
        at java.lang.Thread.run(Thread.java:748)
    Caused by: java.io.IOException: Error while instrumenting com/github/goldy1992/mp3player/client/views/viewholders/MediaPlayerTrackViewHolder.
        at org.jacoco.agent.rt.internal_035b120.core.instr.Instrumenter.instrumentError(Instrumenter.java:158)
        at org.jacoco.agent.rt.internal_035b120.core.instr.Instrumenter.instrument(Instrumenter.java:108)
        at org.jacoco.agent.rt.internal_035b120.CoverageTransformer.transform(CoverageTransformer.java:91)
        ... 86 more
    Caused by: java.lang.IllegalStateException: Cannot process instrumented class com/github/goldy1992/mp3player/client/views/viewholders/MediaPlayerTrackViewHolder. Please supply original non-instrumented classes.
        at org.jacoco.agent.rt.internal_035b120.core.internal.instr.InstrSupport.assertNotInstrumented(InstrSupport.java:237)
        at org.jacoco.agent.rt.internal_035b120.core.internal.instr.ClassInstrumenter.visitField(ClassInstrumenter.java:55)
        at org.jacoco.agent.rt.internal_035b120.asm.ClassVisitor.visitField(ClassVisitor.java:287)
        at org.jacoco.agent.rt.internal_035b120.asm.ClassReader.readField(ClassReader.java:906)
        at org.jacoco.agent.rt.internal_035b120.asm.ClassReader.accept(ClassReader.java:683)
        at org.jacoco.agent.rt.internal_035b120.asm.ClassReader.accept(ClassReader.java:400)
        at org.jacoco.agent.rt.internal_035b120.core.instr.Instrumenter.instrument(Instrumenter.java:88)
        at org.jacoco.agent.rt.internal_035b120.core.instr.Instrumenter.instrument(Instrumenter.java:106)
        ... 87 more

To try and get to the root of the problem I am just running the client unit tests

Client build.gradle

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'de.mannodermaus.android-junit5'
apply plugin: 'jacoco'

android {

    compileSdkVersion TARGET_SDK_VERION
    buildToolsVersion BUILD_TOOLS_VERSION

    defaultConfig {
        minSdkVersion MIN_SDK_VERSION
        targetSdkVersion TARGET_SDK_VERION
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        consumerProguardFiles 'consumer-rules.pro'
        vectorDrawables.useSupportLibrary = true
    }

    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            debuggable true
            minifyEnabled false
            testCoverageEnabled = true
        }
    }
    flavorDimensions 'default'
    productFlavors {
        full {
            dimension = 'default'
        }
        automation {
            dimension = 'default'
        }
    }

    compileOptions {
        incremental = false
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions { jvmTarget = "1.8" }


    testOptions {
        execution 'ANDROID_TEST_ORCHESTRATOR'
        animationsDisabled true

        unitTests {
            includeAndroidResources = true
            returnDefaultValues = true
        }

        unitTests.all {
            testLogging {
                events "passed", "skipped", "failed", "standardOut", "standardError"
                outputs.upToDateWhen {false}
                showStandardStreams = true
            }
        }
    }

    sourceSets {
        main.java.srcDirs += 'src/main/java'
        test.java.srcDirs += 'src/test/java'
        androidTest.java.srcDirs += 'src/androidTest/java'
    }
}

dependencies {
 implementation project(path: ':commons')
 testApi project(":client:testsupport")

 /* MORE DEPENDENCIES NOT RELEVANT TO ISSUE */
}

It may be worth noting that I am using Dagger 2.25.2

Execution data dir: ${projectRootDir}/client/build/jacoco/testFullDebugUnitTest.exec

Source dir: ${projectRootDir}/client/src/main/java

class dir: ${projectRootDir}/client/build/intermediates/javac/fullDebug/classes/, ${projectRootDir}/client/build/tmp/kotlin-classes/fullDebug/

UPDATE 1: From making a new branch and and renaming all the classes and test classes in the client module to CLASS_NAME.kt.old I can confirm that there seems to be no connection between the IllegalClassFormatException and the no coverage.I will therefore update the questions to be the following

UPDATE 2: After further experimenting with update 1 it seems that the exceptions go away and coverage is calculated as expected WHEN there is no dependency on the sub (test) module, i.e. remove the line testApi project(":client:testsupport")from the gradle file. The problem is that I need this testsupportmodule in order to execute my activity tests (which are currently not run because they are in a .old file as per update 1 ^^.

Questions updated as per udate 2 How can I configure JaCoCo to support sub module test implementation of android classes as suggested by the robolectric team in this pull request.

Will update post if more information is required

like image 423
goldy1992 Avatar asked Dec 17 '19 16:12

goldy1992


People also ask

What is instrumented class JaCoCo?

JaCoCo uses class file instrumentation to record execution coverage data. Class files are instrumented on-the-fly using a so called Java agent. This mechanism allows in-memory pre-processing of all class files during class loading independent of the application framework.

Does JaCoCo support Java 11?

JaCoCo now officially supports Java 11 (GitHub #760). Experimental support for Java 13 class files (GitHub #835).

Is JaCoCo instrumentation offline?

One of the main benefits of JaCoCo is the Java agent, which instruments classes on-the-fly. This simplifies code coverage analysis a lot as no pre-instrumentation and classpath tweaking is required.


2 Answers

I just faced the same bug.

After a little investigation, it seems like it is a bug in the Android Gradle Plugin, and it only happens when using com.android.library.

I have reported it and more details here: https://issuetracker.google.com/issues/178015739

While it isn't fixed by the Android team, a workaround is to configure

jacoco {
    toolVersion = "0.7.9"
}

in the build.gradle

It doesn't prevent the error from being logged, but makes it so that the coverage data is collected properly.

like image 129
Paulo Costa Avatar answered Oct 11 '22 14:10

Paulo Costa


Thanks to @Paulo Costa for issue link

For me it was solved by adding

    plugins {
        id 'com.android.library'
        id 'jacoco'
    }
    //these lines
    tasks.withType(Test.class).configureEach {
        jacoco {
            excludes = ["*"]
        }
    }

Credit to : https://issuetracker.google.com/issues/178015739#comment6

like image 26
Manohar Avatar answered Oct 11 '22 12:10

Manohar