How to use JaCoCo Gradle Plugin with TestNG and JUnit? - gradle

I am working on a project where we are using TestNG and JUnit for our tests.
Unfortunately when writing TestNG tests they are not considered in JaCoCo Coverage Reports.
I wrote a testng.gradle file, which I include in each of the build.gradle files (it's a multi-module project):
task testNG(type: Test) { useTestNG() }
test.dependsOn testNG
Both JUnit and TestNG tests work this way.
If I write my testng.gradle like this:
test {
useTestNG()
}
JaCoCo works properly, but obviously only TestNG tests get executed.
How can I fix it? Is it a bug in Gradle's JaCoCo plugin?

Seems that while Gradle JaCoCo Plugin enhances testNG task, so that its execution uses JaCoCo Java agent, but it forgets to update jacocoTestReport task, so that this task doesn't use results of execution of testNG task. Don't know if this is a bug or on purpose, but solution is provided below.
to demonstrate this
file src/main/java/Example.java:
public class Example {
public void junit() {
System.out.println("JUnit");
}
public void testng() {
System.out.println("TestNG");
}
}
file src/test/java/ExampleJUnitTest.java:
import org.junit.Test;
public class ExampleJUnitTest {
#Test
public void test() {
new Example().junit();
}
}
file src/test/java/ExampleTestNGTest.java:
import org.testng.annotations.Test;
public class ExampleTestNGTest {
#Test
public void test() {
new Example().testng();
}
}
file build.gradle:
apply plugin: 'java'
apply plugin: 'jacoco'
repositories {
mavenCentral()
}
dependencies {
testCompile 'org.testng:testng:6.8.8'
testCompile 'junit:junit:4.12'
}
task testNG(type: Test) {
useTestNG()
}
test {
dependsOn testNG
}
After execution of gradle clean test jacocoTestReport -d you'll see in log
java ... -javaagent:.../jacocoagent.jar=destfile=build/jacoco/testNG.exec ...
...
java ... -javaagent:.../jacocoagent.jar=destfile=build/jacoco/test.exec ...
and that directory build/jacoco contains two files - testNG.exec and test.exec, for testNG and for test tasks respectively. While JaCoCo report shows only execution of JUnit by test task.
to solve this
Either instruct task testNG to write execution data into same file as test:
task testNG(type: Test) {
useTestNG()
jacoco {
destinationFile = file("$buildDir/jacoco/test.exec")
}
}
Either instruct task jacocoTestReport to also use testNG.exec file:
jacocoTestReport {
executionData testNG
}
I'm assuming that the same should be done for the case of multi-module project in general and in your case in particular, since Minimal, Complete, and Verifiable example of your multi-module project setup wasn't provided.

The second solution from #Godin's fixed it for me. But to add on that, I found that testNG is not recognized by gradle since it is not matching the right *.exec file under $buildDir/jacoco. In my case it is testNg.exec, so it worked after I include this block in my subproject's build.gradle:
jacocoTestReport {
executionData testNg
}
The first solution does not work for me
task testNG(type: Test) {
useTestNG()
jacoco {
destinationFile = file("$buildDir/jacoco/test.exec")
}
}
I guess it is because the testNG is overwriting the whole file $buildDir/jacoco/test.exec generated from JUnit.

Related

Gradle test suite on precompiled inherit implementation dependencies

I have a testing suite defined on a precompiled script as follows:
...
testing {
suites {
val integrationTest by registering(JvmTestSuite::class) {
testType.set(TestSuiteType.INTEGRATION_TEST)
}
}
}
...
And I have a multi-module project and the test dependencies inherit the dependencies of the module. Example:
dependencies {
implementation(project(":book"))
}
The project book will be available for the test sources.
I want the same thing to happen to the integrationTest sources. How can I do that?
I don't have to manually have to do in the previous example this:
dependencies {
implementation(project(":book"))
integrationTestImplementation(project(":book"))
}
Thanks

Configure Jacoco with gradle and kotlin DSL

I'm trying to configure Jacoco to exclude some classes from analysis but can't find any working example :(
I found some samples with afterEvaluate but no success
src/main/java/org/example/A.java:
package org.example;
class A {
}
src/main/java/org/example/B.java:
package org.example;
class B {
}
src/test/java/org/example/ExampleTest.java:
package org.example;
public class ExampleTest {
#org.junit.Test
public void test() {
new A();
new B();
}
}
build.gradle.kts:
plugins {
java
jacoco
}
repositories {
mavenCentral()
}
dependencies {
testCompile("junit:junit:4.12")
}
using Gradle 5.4.1 execution of gradle test jacocoTestReport produces following report
after addition to build.gradle.kts
tasks.withType<JacocoReport> {
classDirectories.setFrom(
sourceSets.main.get().output.asFileTree.matching {
exclude("org/example/B.class")
}
)
}
execution of the same command produces following report
Just to add to #Godin's awesome answer:
The way #Godin explained it, you would have to run gradle test jacocoTestReport which isn't bad but If you want jacoco to run when you run just with gradle test add this to your build.gralde.kts:
tasks.test {
finalizedBy("jacocoTestReport")
doLast {
println("View code coverage at:")
println("file://$buildDir/reports/jacoco/test/html/index.html")
}
}
I've managed to exclude this way:
tasks.jacocoTestReport {
classDirectories.setFrom(
files(classDirectories.files.map {
fileTree(it) {
exclude(
"com/example/integration/**",
"com/example/application/*Ext*"
)
}
})
)
}
Taken from here

Is there a Gradle task to download testRuntime dependencies?

Is there a command that will instruct Gradle to resolve and download all testRuntime dependencies, but not run the tests?
Preferably, I want to do this without writing a custom task (such that the command can be run against any Gradle project).
For example, if my build.gradle has this dependency:
dependencies {
// ...
testRuntime "org.seleniumhq.selenium:selenium-htmlunit-driver:2.47.1"
}
The JAR files associated with selenium-htmlunit-driver are not downloaded until I run gradle test, which also runs the tests. I can download all other dependencies by running gradle testClasses, but not the testRuntime deps.
Put the following in a file called resolve.gradle
gradle.allprojects { project ->
project.task('resolveTestRuntime') {
doLast {
project.configurations.testRuntime.resolve()
}
}
}
Then run resolve.gradle as an init script
gradlew --init-script resolve.gradle resolveTestRuntime
Modifying the answer from Lance Java into a valid Init script, I was able to accomplish this with the following resolve.gradle:
apply plugin:MyInitPlugin
class MyInitPlugin implements Plugin<Gradle> {
#Override
void apply(Gradle gradle) {
gradle.allprojects{ project ->
project.task('resolveTestRuntime') {
doLast {
project.configurations.testRuntime.resolve()
}
}
}
}
}
Then running:
gradlew --init-script resolve.gradle resolveTestRuntime

Import Cucumber with Gradle

I want to import cucumber.api.java.en.* into my groovy files, but cucmber.api will not be recognized as in my classpath. Thus every #Given or #When annotation is not recognized.
When I build with ./gradlew cucumber the .feature file is found and missing snippets are shown in the console. What do I have to include in my build.gradle to add above import into my classpath?
My gradle version is 2.2 and the cucumber related parts of my build.gradle file look like this:
dependencies {
testCompile 'info.cukes:cucumber-java:1.2.4'
testCompile 'info.cukes:cucumber-junit:1.2.4'
}
test {
testLogging.showStandardStreams = true
systemProperties System.getProperties()
}
configurations {
cucumberRuntime {
extendsFrom testRuntime
}
}
task cucumber() {
dependsOn assemble, compileTestJava
doLast {
javaexec {
main = "cucumber.api.cli.Main"
classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output
args = ['-f', 'pretty', '--glue', 'gradle.cucumber', 'src/test/resources']
}
}
}
What am I missing?
You include info.cukes:cucumber-java:1.2.4 which is the jar containing the annotations you are missing. They are expected to be available in your test classpath.
To me, it sounds as an issue with your IDE.
If you are using IntelliJ IDEA, try to re-import the project. Click on the two rotating arrows in your Gradle tab and refresh the project.

Not able to execute Jbehave with Gradle using Serenity Framewrok

I am using Serenity - JBehave framework. After creation of sample script, I am able to execute Junit runner class from eClipse however when I am trying to execute any of the below command from command prompt it is giving me error.
$gradle clean test aggregate
$gradle clean test
$gradle clean build
The error message is same in all cases, as below:
org.gradle.TestRunnerClass > initializationError FAILED
java.lang.RuntimeException
Caused by: java.lang.RuntimeException
Caused by: java.lang.IllegalArgumentException
Caused by: java.lang.ClassNotFoundException
1 test completed, 1 failed
:test FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///C:/$ /build/reports/tests/index.html
Below are the details:
Test Runner class:
package org.gradle;
import net.serenitybdd.jbehave.SerenityStories;
public class TestRunnerClass extends SerenityStories{}
Sample Step Definition class:
package org.gradle.stepDef;
import net.thucydides.core.annotations.Step;
import net.thucydides.core.annotations.Steps;
import org.jbehave.core.annotations.Given;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.annotations.When;
public class StepDefSticky {
#Given("User is on Sticky note home page")
public void givenUserIsOnStickyNoteHomePage() {
System.out.println("I am in Given");
}
#When("User clicks on Add Note button")
public void whenUserClicksOnAddNoteButton() {
System.out.println("I am in When");
}
#Then("Sticky note pop up should get open")
public void thenStickyNotePopUpShouldGetOpen() {
System.out.println("I am in Then");
}
}
Please see the package structure carefully.
Below is the build.gradle I am using
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'net.serenity-bdd.aggregator'
apply plugin: 'com.jfrog.bintray'
sourceCompatibility = 1.8
version = '1.0'
def poiVersion = "3.10.1"
repositories {
maven { url "repoUrl" }
}
buildscript {
repositories {
maven { url "repoURL" }
}
dependencies {
classpath("net.serenity-bdd:serenity-gradle-plugin:1.0.47")
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:0.6'
classpath 'org.ajoberstar:gradle-git:0.12.0'
}
}
ext {
bintrayBaseUrl = 'https://api.bintray.com/maven'
bintrayRepository = 'maven'
bintrayPackage = 'serenity-cucumber'
projectDescription = 'Serenity Cucumber integration'
if (!project.hasProperty("bintrayUsername")) {
bintrayUsername = 'wakaleo'
}
if (!project.hasProperty("bintrayApiKey")) {
bintrayApiKey = ''
}
serenityCoreVersion = '1.0.47'
cucumberJVMVersion = '1.2.2'
}
dependencies {
testCompile('junit:junit:4.11')
testCompile('org.assertj:assertj-core:1.7.0')
testCompile('org.slf4j:slf4j-simple:1.7.7')
//JBehave jar files
testCompile 'net.serenity-bdd:core:1.0.47'
testCompile 'net.serenity-bdd:serenity-jbehave:1.0.21'
testCompile 'net.serenity-bdd:serenity-junit:1.0.47'
// Apache POI plugin for excel read
compile "org.apache.poi:poi:${poiVersion}"
compile "org.apache.poi:poi-ooxml:${poiVersion}"
compile "org.apache.poi:ooxml-schemas:1.1"
}
gradle.startParameter.continueOnFailure = true
uploadArchives {
repositories { flatDir { dirs 'repos' } }
}
task wrapper(type: Wrapper) { gradleVersion = '2.3' }
I have stored the .story file under the src/test/resources package.
Please help me to understand where I am making mistake. Thanks for your help on this.
Enable standard out and standard error in your build.gradle file:
test {
testLogging {
showStandardStreams = true
}
}
And to make sure all your stories run, add a TestSuite class:
#RunWith(Suite.class)
#SuiteClasses({ Story1.class, Story2.class})
public class TestSuite { }
Note: Story1 & Story2 are the names of the test runners to match a JBehave Gherkin files named Story1.story & Story2.story & step files names Story1Steps.java & Story2Steps.java according to Serenity naming conventions.

Resources