Search code examples
gradlebuild.gradlejunit5jacocojunit-jupiter

How to configure build.gradle using Junit5 and Jacoco for test coverage


I am trying to configure the build.gradle file so that it supports both Junit 5 and Jacoco. I was using useJunitPlatform before, but it generates another errors. I also tried some other ways, but none can successfully generate Jacoco report. This configuration however, sucessfully generated Jacoco report for me, but it also gave me an exception. Below is my build.gradle file.

plugins {
    // Build "fat" jars for deployment
    id 'com.github.johnrengelman.shadow' version '5.2.0'

    // Apply the java plugin to add support for Java
    id 'java'

    // Apply the application plugin to add support for building a CLI application.
    id 'application'

    // Deploy directly to heroku without using Git
    id "com.heroku.sdk.heroku-gradle" version "1.0.4"

    // Lombok provides shorthand for repetitive Java tasks
    id "io.freefair.lombok" version "4.1.6"

    // Spotless to format code easily
    id "com.diffplug.gradle.spotless" version "3.27.1"

    // Jacoco test coverage
    id 'jacoco'
}

repositories {
    // Use jcenter for resolving dependencies.
    // You can declare any Maven/Ivy/file repository here.
    jcenter()
}

dependencies {
    // Simple HTTP framework - http://sparkjava.com/
    implementation 'com.sparkjava:spark-core:2.9.1'

    // Basic logging support; used by Spark
    implementation "org.slf4j:slf4j-simple:1.7.25"

    // Jackson to serialize/deserialize JSON
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.10.2'

    // Use JUnit Jupiter API for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'

    testImplementation 'org.junit.platform:junit-platform-launcher:1.5.2'

    // Use JUnit Jupiter Engine for testing.
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'

    // Use dagger for dependency injection
    implementation 'com.google.dagger:dagger:2.26'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.26'

    // Annotations such as Nullable
    implementation 'com.google.code.findbugs:annotations:3.0.1'

    // Force JRE Guava to work around issues with Truth
    testImplementation "com.google.guava:guava:28.2-jre"

    // Fluent assertions for testing
    testImplementation 'com.google.truth:truth:1.0.1'

    // MongoDB client
    implementation 'org.mongodb:mongodb-driver:3.12.1'
}

application {
    // Define the main class for the application.
    mainClassName = 'edu.northeastern.cs5500.delivery.App'
}

jacoco {
    toolVersion = "0.8.5"
    reportsDir = file("$buildDir/customJacocoReportDir")
}

jacocoTestReport {
    reports {
        xml.enabled false
        csv.enabled false
        html.destination file("${buildDir}/jacocoHtml")
    }
    afterEvaluate {
        classDirectories.from = files(classDirectories.files.collect {
            fileTree(dir: it, exclude: [
                    '**/model/**',
                    '**/view/**',
                    '**/utils/**',
                    '**/service/**'
            ])
        })
    }
    doLast {
        println "file://$buildDir/jacocoHtml/index.html"
    }
}

test {
    // Use junit platform for unit tests
    useJUnit()
    finalizedBy jacocoTestReport
}

// Heroku will run the 'stage' task on deployment via git
task stage(dependsOn: ['clean', 'shadowJar'])
shadowJar.mustRunAfter clean

// Force all builds to be clean builds due to Dagger problems
build.mustRunAfter clean
build.dependsOn += 'clean'

run.mustRunAfter clean
run.dependsOn += 'clean'

// Target Java 1.11 - make sure system.properties matches this as well
sourceCompatibility = 1.11
targetCompatibility = 1.11

sourceSets {
    main {
        java {
            srcDirs 'src/main/java'
            srcDirs 'build/generated/sources/annotationProcessor/java/main'
        }
    }
    test {
        java {
            srcDirs 'src/test/java'
            srcDirs 'build/generated/sources/annotationProcessor/java/test'
        }
    }
}

spotless {
    format 'misc', {
        target '**/*.gradle', '**/*.md', '**/.gitignore'
        targetExclude 'build/**'

        trimTrailingWhitespace()
        indentWithSpaces()
        endWithNewline()
        paddedCell()
    }
    java {
        targetExclude 'build/**'
        googleJavaFormat().aosp()
    }
}

The error that occurs every time I built is shown below

java.lang.instrument.IllegalClassFormatException: Error while instrumenting sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo.
        at org.jacoco.agent.rt.internal_43f5073.CoverageTransformer.transform(CoverageTransformer.java:94)
        at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
        at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
        at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
        at java.base/java.lang.ClassLoader.defineClass2(Native Method)
        at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1108)
        at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:183)
        at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:784)
        at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:705)
        at java.base/jdk.internal.loader.BuiltinClassLoader.findClass(BuiltinClassLoader.java:586)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:634)
        at java.base/java.lang.Class.forName(Class.java:546)
        at java.base/java.util.ServiceLoader.loadProvider(ServiceLoader.java:854)
        at java.base/java.util.ServiceLoader$ModuleServicesLookupIterator.hasNext(ServiceLoader.java:1078)
        at java.base/java.util.ServiceLoader$2.hasNext(ServiceLoader.java:1301)
        at java.base/java.util.ServiceLoader$3.hasNext(ServiceLoader.java:1386)
        at java.base/sun.util.cldr.CLDRLocaleProviderAdapter$1.run(CLDRLocaleProviderAdapter.java:89)
        at java.base/sun.util.cldr.CLDRLocaleProviderAdapter$1.run(CLDRLocaleProviderAdapter.java:86)
        at java.base/java.security.AccessController.doPrivileged(AccessController.java:554)
        at java.base/sun.util.cldr.CLDRLocaleProviderAdapter.<init>(CLDRLocaleProviderAdapter.java:86)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:64)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
        at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
        at java.base/sun.util.locale.provider.LocaleProviderAdapter.forType(LocaleProviderAdapter.java:188)
        at java.base/sun.util.locale.provider.LocaleProviderAdapter.findAdapter(LocaleProviderAdapter.java:287)
        at java.base/sun.util.locale.provider.LocaleProviderAdapter.getAdapter(LocaleProviderAdapter.java:258)
        at java.base/java.util.Calendar.createCalendar(Calendar.java:1693)
        at java.base/java.util.Calendar.getInstance(Calendar.java:1661)
        at java.base/java.text.SimpleDateFormat.initializeCalendar(SimpleDateFormat.java:677)
        at java.base/java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:621)
        at java.base/java.text.SimpleDateFormat.<init>(SimpleDateFormat.java:600)
        at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.getLastResortErrorLogFile(SystemApplicationClassLoaderWorker.java:162)
        at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:111)
        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)
Caused by: java.io.IOException: Error while instrumenting sun/util/resources/cldr/provider/CLDRLocaleDataMetaInfo.
        at org.jacoco.agent.rt.internal_43f5073.core.instr.Instrumenter.instrumentError(Instrumenter.java:159)
        at org.jacoco.agent.rt.internal_43f5073.core.instr.Instrumenter.instrument(Instrumenter.java:109)
        at org.jacoco.agent.rt.internal_43f5073.CoverageTransformer.transform(CoverageTransformer.java:92)
        ... 37 more
Caused by: java.lang.IllegalArgumentException: Unsupported class file major version 59
        at org.jacoco.agent.rt.internal_43f5073.asm.ClassReader.<init>(ClassReader.java:195)
        at org.jacoco.agent.rt.internal_43f5073.asm.ClassReader.<init>(ClassReader.java:176)
        at org.jacoco.agent.rt.internal_43f5073.asm.ClassReader.<init>(ClassReader.java:162)
        at org.jacoco.agent.rt.internal_43f5073.core.internal.instr.InstrSupport.classReaderFor(InstrSupport.java:280)
        at org.jacoco.agent.rt.internal_43f5073.core.instr.Instrumenter.instrument(Instrumenter.java:75)
        at org.jacoco.agent.rt.internal_43f5073.core.instr.Instrumenter.instrument(Instrumenter.java:107)
        ... 38 more

Thanks for any help!


Solution

  • Based on your error message

    Caused by: java.lang.IllegalArgumentException: Unsupported class file major version 59

    and according to https://en.wikipedia.org/wiki/Java_class_file you're using Java 15.

    According to https://www.jacoco.org/jacoco/trunk/doc/changes.html support for Java 15 was added in JaCoCo version 0.8.6

    So either you don't need Java 15 and can use earlier version such as 11 (LTS), or you need to change

    jacoco {
        toolVersion = "0.8.5"
    

    on

    jacoco {
        toolVersion = "0.8.6"