Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testng, Emma, Cobertura, coverage and JDK 7 result in ClassFormatError and VerifyError

I have switched to the newest JDK 7 and I am having problems with running testng unit test on byte code that is fiddled by emma coverage tool. None of my test cases are run correctly and for most of them I am receiving such errors.

 java.lang.ClassFormatError: Illegal local variable table length 10 in method measurement.meter.AbstractSerialPortMeter.<init>(Lmeasurement/meter/SerialPort;)V at measurement.meter.Elc3133aTest.setUp(Elc3133aTest.java:42)

I have found an article here JSR 292 Goodness Fast Code Coverage Tool Less 10k, which is saying that "JSR 292 introduces a new bytecode instruction invokedynamic but also several new kind of constant pool constants. Which means that most of the tools that parse bytecodes like ASM, BCEL, findbugs or EMMA will need to be updated to be java 7 compatible."

Checked Emma homepage, but it looks like it has not been updated for a long long time.

Has anybody solved a similar problem?

I have also tried with Cobertura. It looks to work a bit better but I am getting a lot of exceptions of type VerifyError.

java.lang.VerifyError: Expecting a stackmap frame at branch target 85 in method measurement.meter.AbstractSerialPortMeter.close()V at offset 26
at measurement.meter.AbstractSerialPortMeterTest.setUp(AbstractSerialPortMeterTest.java:27)
like image 546
Jagger Avatar asked Aug 10 '11 12:08

Jagger


4 Answers

I had same problem using maven cobertura plugin. All tests failed when run from cobertura:report. But all tests succeeded when run directly from surefire plugin. As some of you already said the problem is that coberture byte code instrumentation of is not compatible with JDK7.

You can see here http://vikashazrati.wordpress.com/2011/10/09/quicktip-verifyerror-with-jdk-7/ that the exception is related to the "new type checker with StackMapTable attributes" (see: -X:+UseSplitVerifier JVM option in http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html).

So my solution is to configure surefire-plugin to always execute the tests with JVM arg "-XX:-UseSplitVerifier. It works well with and without cobertura instrumentation.

My surefire configuration in maven:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.12</version>
    <configuration>
        <argLine>-XX:-UseSplitVerifier</argLine>
    </configuration>
</plugin>
like image 126
Pedro Ballesteros Avatar answered Nov 04 '22 20:11

Pedro Ballesteros


I had the same issue. Fortunately beta works with JDK 7.
Update site link: http://download.eclipselab.org/eclemma/beta/2.0.0/update/
This link should be used in Eclipse:

Help -> Install new software... -> Add...


Rest should be easy ;)

like image 5
wieczorek1990 Avatar answered Nov 04 '22 22:11

wieczorek1990


I got Gradle 1.0M9, Java 7 and EMMA 2.1 working with the patches suggested here: using the jvm argument.

Details here... http://marcellodesales.wordpress.com/2012/04/03/running-emma-code-test-coverage-with-java-7-and-gradle-1-0m9/?preview=true&preview_id=179&preview_nonce=261e892908

configurations{
  emma
}

dependencies {
  // EMMS Code Coverage
  emma "emma:emma:2.1.5320"
  emma "emma:emma_ant:2.1.5320"
  ...
  testCompile group: 'junit', name: 'junit', version: '4.9'
}

test {
    // add EMMA related JVM args to our tests
    jvmArgs "-XX:-UseSplitVerifier", "-Demma.coverage.out.file=$buildDir/tmp/emma/metadata.emma", "-Demma.coverage.out.merge=true"

    doFirst {
       println "Instrumenting the classes at " + sourceSets.main.output.classesDir.absolutePath
       // define the custom EMMA ant tasks
       ant.taskdef( resource:"emma_ant.properties", classpath: configurations.emma.asPath)

       ant.path(id:"run.classpath") {
          pathelement(location:sourceSets.main.output.classesDir.absolutePath)
       }
       def emmaInstDir = new File(sourceSets.main.output.classesDir.parentFile.parentFile, "tmp/emma/instr")
       emmaInstDir.mkdirs()
       println "Creating $emmaInstDir to instrument from " +       sourceSets.main.output.classesDir.absolutePath
       // instruct our compiled classes and store them at $buildDir/tmp/emma/instr
       ant.emma(enabled: 'true', verbosity:'info'){
          instr(merge:"true", destdir: emmaInstDir.absolutePath, instrpathref:"run.classpath",
                metadatafile: new File(emmaInstDir, '/metadata.emma').absolutePath) {
             instrpath {
             fileset(dir:sourceSets.main.output.classesDir.absolutePath, includes:"**/*.class")
             }
          }
       }
       setClasspath(files("$buildDir/tmp/emma/instr") + configurations.emma +    getClasspath())
    }

    // The report should be generated directly after the tests are done.
    // We create three types (txt, html, xml) of reports here. Running your build script now should
    // result in output like that:
    doLast {
       def srcDir = sourceSets.main.java.srcDirs.toArray()[0]
       println "Creating test coverage reports for classes " + srcDir
       def emmaInstDir = new File(sourceSets.main.output.classesDir.parentFile.parentFile, "tmp/emma")
       ant.emma(enabled:"true"){
          new File("$buildDir/reports/emma").mkdirs()
          report(sourcepath: srcDir){
             fileset(dir: emmaInstDir.absolutePath){
                include(name:"**/*.emma")
             }
             txt(outfile:"$buildDir/reports/emma/coverage.txt")
             html(outfile:"$buildDir/reports/emma/coverage.html")
             xml(outfile:"$buildDir/reports/emma/coverage.xml")
          }
       }
       println "Test coverage reports available at $buildDir/reports/emma."
       println "txt: $buildDir/reports/emma/coverage.txt"
       println "Test $buildDir/reports/emma/coverage.html"
       println "Test $buildDir/reports/emma/coverage.xml"
    }
}

Running "gradle test" gives the following:

marcello@hawaii:/u1/development/workspaces/open-source/interviews/vmware$ gradle test
:compileJava
:processResources UP-TO-DATE
:classes
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
Instrumenting the classes at /u1/development/workspaces/open-source/interviews/vmware/build/classes/main
Creating /u1/development/workspaces/open-source/interviews/vmware/build/tmp/emma/instr to instrument from /u1/development/workspaces/open-source/interviews/vmware/build/classes/main
Creating test coverage reports for classes /u1/development/workspaces/open-source/interviews/vmware/src/main/java
Test coverage reports available at /u1/development/workspaces/open-source/interviews/vmware/build/reports/emma.
txt: /u1/development/workspaces/open-source/interviews/vmware/build/reports/emma/coverage.txt
Test /u1/development/workspaces/open-source/interviews/vmware/build/reports/emma/coverage.html
Test /u1/development/workspaces/open-source/interviews/vmware/build/reports/emma/coverage.xml

BUILD SUCCESSFUL
like image 2
Marcello de Sales Avatar answered Nov 04 '22 22:11

Marcello de Sales


Emma works if you do not use new language features (like try-with-resources, etc.). You can use Java 7 using new libraries (Paths, DirectoryStream, etc.). I know this would be not a solution to your problem, but if you want to only check "how JDK 7 performs" it may work...

like image 1
rafalmag Avatar answered Nov 04 '22 20:11

rafalmag