Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document code or automatically configure Jacoco with Junit 5 Gradle Plugin #1024

Closed
1 task
JLLeitschuh opened this issue Aug 17, 2017 · 14 comments
Closed
1 task

Comments

@JLLeitschuh
Copy link
Contributor

JLLeitschuh commented Aug 17, 2017

Feature (or Documentation) Request

Should the Junit 5 plugin automatically configure the junitPlatformTest task to use Jacoco if it detects the plugin?

Currently configuring jacoco with Junit 5 requires a bit of digging into the DSL and figuring out its intricacies.

Perhaps configure the Junit5 plugin should be expanded to have a enableJacoco flag that will add a jacocoJunit5TestReport task if set to true? What are the teams thoughts?

Current solutions

Anyone looking to configure jacoco with Junit 5 using the new Gradle Kotlin DSL you currently need to use a bit of a workaround because of a kotlin compiler bug. This code is known to work with Gradle 4.1

// Don't use this sample, see below
afterEvaluate {
    val junitPlatformTest by tasks
    jacoco {
        applyToHelper(junitPlatformTest)
    }
    task<JacocoReport>("jacocoJunit5TestReport") {
        executionData(junitPlatformTest)
        sourceSets(java.sourceSets["main"])
        sourceDirectories = files(java.sourceSets["main"].allSource.srcDirs)
        classDirectories = files(java.sourceSets["main"].output)
    }
}

/**
 * Workaround fix for calling [org.gradle.testing.jacoco.plugins.JacocoPluginExtension.applyTo]
 *
 * [Issue details here](https://github.com/gradle/kotlin-dsl/issues/458)
 */
fun org.gradle.testing.jacoco.plugins.JacocoPluginExtension.applyToHelper(task : Task) {
    val method = this::class.java.getMethod("applyTo", Task::class.java)
    method.invoke(this, task)
}

EDIT

Better solution with less code:

afterEvaluate {
    val junitPlatformTest : JavaExec by tasks
    jacoco {
        applyTo(junitPlatformTest)
    }
    task<JacocoReport>("jacocoJunit5TestReport") {
        executionData(junitPlatformTest)
        sourceSets(java.sourceSets["main"])
        sourceDirectories = files(java.sourceSets["main"].allSource.srcDirs)
        classDirectories = files(java.sourceSets["main"].output)
    }
}

Deliverables

  • Documentation about how to configure Jacoco with Gradle or add code to the plugin to do it automatically
@marcphilipp
Copy link
Member

IIRC Currently, the Jacoco plugin hooks into the test task. Could it be extended to support junitPlatformTest (at least until Gradle provides core support for the new JUnit platform)?

@alixwar
Copy link

alixwar commented Sep 20, 2017

@JLLeitschuh Do you know of a workaround for Gradle (Android) Java?

My attempt unfortunately only results in code coverage data for JUnit4 tests

@JLLeitschuh
Copy link
Contributor Author

Does the android plugin do something special for testing? I'm not totally certain because I've never done anything with it.

I guess my first question is can you get the junit 5 plugin to correctly execute your tests? Once you have that working the above should work.
If you need the same logic but for groovy I can provide an example of that if it would help.

@alixwar
Copy link

alixwar commented Sep 21, 2017

@JLLeitschuh I have done the following for each submodule in the project:

project.afterEvaluate {
    apply plugin: "jacoco"
    jacoco {
        applyTo junitPlatformTestDebug
    }
}:

This is enough to generate code coverage for JUnit4 tests (inluding tests annotated @RunWith(MockitoJUnitRunner.class)) under the JUnit Vintage runner but not JUnit5 tests or Robolectric tests (JUnit4 tests annotated @RunWith(RobolectricTestRunner.class)). Would your groovy example look any different?

Does the android plugin do something special for testing?

Do you mean the Android Gradle plugin or the Android JUnit 5 plugin?

@mannodermaus
Copy link

mannodermaus commented Sep 23, 2017

Does the android plugin do something special for testing?

As opposed to the Java-based Gradle plugin for JUnit 5 provided by the junit5 team? It basically only extends its core functionality with the variant-awareness that Android projects have. Instead of adding just a single junitPlatformTest task, the android-junit5 plugin applies a task per variant, junitPlatformTestDebug & junitPlatformTestRelease, while also taking care of potential product flavors.

@alixwar
Copy link

alixwar commented Sep 27, 2017

@JLLeitschuh Any thoughts on the explanation from @mannodermaus ? Is there something that I or someone else can do to help clarify the issue?

@JLLeitschuh
Copy link
Contributor Author

I don't work with any projects that use gradle for building android projects. I'm assuming that as long as you can get your android tests to run correctly using the junitPlatformTest task then the code snippet that I have provided should work.

If you have specific behaviour problems that you are experiencing then I may be able to help. At the moment I'm not totally certain I understand what the problem is.

@mannodermaus
Copy link

mannodermaus commented Sep 27, 2017

As discussed over at mannodermaus/android-junit5#4, the latest SNAPSHOT release of the Android-based plugin for JUnit 5 implements the first iteration of support for Jacoco out of the box, so there's nothing to be done from you guys in that regard.

As for the Java-based JUnit 5 Gradle plugin, it could be a nice improvement to apply the code snippet for Jacoco integration directly through the plugin in a future release. In the android-junit5 plugin, I'm conditionally extending each JUnit 5 task with a corresponding Jacoco reporting task only if the plugin is found to exist in a module.

@alixwar
Copy link

alixwar commented Sep 28, 2017

I'm happy to report that from my perspective the issue with JUnit5 is resolved on Android. It works fine with the latest snapshot release of the plugin.

@alixwar
Copy link

alixwar commented Sep 28, 2017

@JLLeitschuh I've created a sample project with the following tests (for a related issue):

  • Vanilla (run by JUnit5 vintage runner) JUnit 4 test (OK)
  • Vanilla (run by JUnit5 Juniper runner) JUnit 5 test (OK)
  • JUnit 4 (run by JUnit5 vintage runner) test using MockitoTestRunner (OK)
  • JUnit 4 (run by JUnit5 vintage runner) test using RobolectricTestRunner (No test coverage)

Sample project: mannodermaus/android-junit5#18

Steps to reproduce:

  1. In the sample-robolectric folder, run: ..\gradlew clean jacocoTestReportDebug
  2. Examine the resulting $buildDir\jacoco\junitPlatformTestDebug.exec

Expected:
Code coverage for Foo.junit4robolectric(), Foo.junit4(), Foo.junit4mockito() and Foo.junit5()

Actual:
No code coverage for Foo.junit4robolectric()

I realize that this is more of a problem for the Robolectric project (I've reported it here: robolectric/robolectric#3397) but if any of you guys, who know much more about this than I, could take a quick peek and pin point what seems to be wrong it would be easier for someone else to find a workaround or to make a pull request and fix the issue in the Robolectric project so that Android developers (Robolectric is quite common) can start with JUnit5.

@domhauton
Copy link

domhauton commented Dec 29, 2017

@JLLeitschuh 's solution worked but the idea groovy linter wasn't too happy. This was my final solution.

For Gradle 4.4.1

apply plugin: 'jacoco'

afterEvaluate {
    def junitPlatformTestTask = (JavaExec) project.tasks.getByName('junitPlatformTest')

    jacoco {
        applyTo(junitPlatformTestTask)
    }

    project.task(type: JacocoReport, "jacocoJupTestReport") {
        executionData(junitPlatformTestTask)
        sourceSets(sourceSets.main)
        sourceDirectories = files(sourceSets.main.allSource.srcDirs)
        classDirectories = files(sourceSets.main.output)

        reports {
            xml.enabled true
            xml.destination file("${buildDir}/jacoco/report.xml")
            html.enabled true
            html.destination file("${buildDir}/jacoco/html")
        }
    }

    check.dependsOn jacocoJupTestReport
}

gurkenlabs pushed a commit to gurkenlabs/litiengine that referenced this issue Feb 10, 2018
clean up all old JUnit dependencies (the mp3spi reference junit 3.8.).
Implement jacoco support for the JUnit 5 test results (see: junit-team/junit5#1024)

Closes #79
@Thunderforge
Copy link

@domhauton Is there a better solution now that Gradle 4.6 is out with a new way of handling JUnit 5?

@sormuras
Copy link
Member

@Thunderforge I guess, with Gradle 4.6 and useJUnitPlatform() you can use the JaCoCo plugin as-is.

@marcphilipp
Copy link
Member

Since Gradle now provides native support for running tests on the JUnit Platform, JaCoCo should work without any extra configuration. We've decided to deprecate our custom plugin (see #1317 for details) and not add any new features to it. Thus, I'm closing this issue.

@marcphilipp marcphilipp removed this from the 5.x Backlog milestone Mar 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants