How can I create integrations tests using Gradle 5.2 and JUnit 5.3 in a multi-project build file?
This is my current build file:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.10"
classpath 'org.owasp:dependency-check-gradle:5.0.0-M2'
}
}
allprojects {
defaultTasks 'clean', 'build', 'publish', 'installDist'
group = 'coyote'
version = '0.1.0'
}
subprojects {
apply plugin: 'java'
apply plugin: 'jacoco'
apply plugin: "com.github.spotbugs"
apply plugin: 'org.owasp.dependencycheck'
apply plugin: 'maven-publish'
apply plugin: 'application'
apply plugin: 'eclipse'
apply plugin: 'idea'
repositories {
jcenter()
mavenCentral()
}
dependencies {
testImplementation ("org.junit.jupiter:junit-jupiter-api:5.3.2")
testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.3.2")
spotbugsPlugins ("com.h3xstream.findsecbugs:findsecbugs-plugin:1.8.0")
}
tasks.withType(Test) {
useJUnitPlatform()
}
apply from: "$rootDir/integration-test.gradle"
check.dependsOn jacocoTestCoverageVerification
check.dependsOn dependencyCheckAnalyze
spotbugs {
effort = "max"
reportLevel = "low"
ignoreFailures = true
showProgress = true
}
jacocoTestReport {
reports {
xml.enabled true
html.enabled true
}
}
check.dependsOn jacocoTestReport
tasks.withType(com.github.spotbugs.SpotBugsTask) {
reports {
xml.enabled false
html.enabled true
}
}
}
The integration-test.gradle file I am applying on line 46 contains the following:
sourceSets {
itest {
compileClasspath += sourceSets.main.output + configurations.testCompile
runtimeClasspath += output + compileClasspath + configurations.testRuntime
}
}
idea {
module {
testSourceDirs += sourceSets.itest.java.srcDirs
testResourceDirs += sourceSets.itest.resources.srcDirs
scopes.TEST.plus += [configurations.itestCompile]
}
}
task itest(type: Test) {
description = 'Runs the integration tests.'
group = 'verification'
testClassesDirs = sourceSets.itest.output.classesDirs
classpath = sourceSets.itest.runtimeClasspath
outputs.upToDateWhen { false }
}
Everything seems to work well within Intellij, but JUnit5 is not being added to the classpath, so any tests in the itest directories cannot find the JUnit libraries.
Running gradlew itest fails with similar results with the JUnit classes not being found.
I have tried to add use useJUnitPlatform() directly in the itest task, but with no success. I have also tried placing everything in the build.gradle file with no success.
Eventually, I'd like to use the same pattern to define load and security testing, running them separately as part of a CI/CD pipeline so placing everything neatly in their own directories under their respective projects is preferred to mixing everything in one test directory and using tags.
This is also helping other teams model CI/CD practices, so using Gradle 5 and JUnit 5 as designed is preferred as opposed to work-arounds or hacks to make things work. It's acceptable to learn that these versions don't work together or that there are currently defects\issues preventing this approach. Hopefully this is not the issue and I'm just missing something simple.
The solution is I needed to include the JUnit 5 dependencies myself. The following is the correct integration-test.gradle file:
sourceSets {
itest {
compileClasspath += sourceSets.main.output + configurations.testCompile
runtimeClasspath += output + compileClasspath + configurations.testRuntime
}
}
idea {
module {
testSourceDirs += sourceSets.itest.java.srcDirs
testResourceDirs += sourceSets.itest.resources.srcDirs
scopes.TEST.plus += [configurations.itestCompile]
}
}
dependencies {
itestImplementation ("org.junit.jupiter:junit-jupiter-api:5.3.2")
itestRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.3.2")
}
task itest(type: Test) {
description = 'Runs the integration tests.'
group = 'verification'
testClassesDirs = sourceSets.itest.output.classesDirs
classpath = sourceSets.itest.runtimeClasspath
outputs.upToDateWhen { false }
}
Related
This question already has an answer here:
Configuration for Gradle 4.7 to generate the HTML report for JUnit 5 tests
(1 answer)
Closed 4 years ago.
I am trying to generate HTML report of JUnit 5 test case.
Here is my Gradle.build file
buildscript {
ext {
springBootVersion = '2.0.0.M3'
}
repositories {
maven { url 'https://zz-artifactory.zzzz.com/artifactory/maven' }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.2.0-M1'
classpath "io.spring.gradle:dependency-management-plugin:1.0.0.RC1"
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'org.junit.platform.gradle.plugin'
apply plugin: "io.spring.dependency-management"
apply from: "CodeCoverage.gradle"
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8
dependencies {
compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2')
compile('org.mybatis.spring.boot:mybatis-spring-boot:1.3.2')
compile('org.mybatis.spring.boot:mybatis-spring-boot-starter-test:1.3.2')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-aop')
compile("org.junit.jupiter:junit-jupiter-api:5.2.0-M1")
compile('org.junit.jupiter:junit-jupiter-migrationsupport:5.0.2')
compile("org.junit.jupiter:junit-jupiter-engine:5.2.0-M1")
compile("junit:junit:4.12")
compile("org.junit.vintage:junit-vintage-engine:5.2.0-M1")
compile(group: 'org.junit.platform', name: 'junit-platform-launcher', version: '1.2.0-M1')
compile(group: 'org.junit.platform', name: 'junit-platform-runner', version: '1.2.0-M1')
testCompile('com.h2database:h2:1.4.196')
testCompile('org.mockito:mockito-all:2.0.2-beta')
testCompile('org.mockito:mockito-core:2.8.9')
}
test {
useJUnitPlatform()
}
junitPlatform {
// platformVersion '1.2.0-M1'
filters {
engines {
// include 'junit-jupiter', 'junit-vintage'
// exclude 'custom-engine'
}
tags {
include 'Smoke'
//exclude 'slow'
}
}
}
subprojects {
apply plugin: 'java'
test {
reports.html.enabled = false
}
}
task testReport(type: TestReport) {
destinationDir = file("$buildDir/reports123/allTests")
// Include the results from the `test` task in all subprojects
reportOn subprojects*.test
}
I have used testReport as per
Gradle docs Links
When i run the Gradle task, It runs all the test case, generate XML reprts, but doesnot generate HTML report
In the build log, i see
:testReport NO-SOURCE
any suggestion why it says NO-SOURCE ??
Thanks
You are doing one thing too many. You should either use 'org.junit.platform.gradle.plugin' or test { useJUnitPlatform } but not both.
The standard gradle (html) test reporting will only work with the latter.
My build.gradle is:
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'org.junit.platform.gradle.plugin'
apply plugin: 'io.qameta.allure'
defaultTasks 'clean', 'test'
ext.junitJupiterVersion = '5.0.0-M4'
ext.selenideVersion = '4.4.3'
compileTestJava {
sourceCompatibility = 1.8
targetCompatibility = 1.8
options.encoding = 'UTF-8'
options.compilerArgs += "-parameters"
}
compileJava.options.encoding = 'UTF-8'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
repositories {
jcenter()
mavenCentral()
}
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0-M4'
classpath 'io.qameta.allure:allure-gradle:2.3'
}
}
allure {
aspectjweaver = true
autoconfigure = true
version = '2.1.1'
}
configurations {
agent
}
dependencies {
// JUnit5
compile("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}")
compile("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}")
// Selenide
compile("com.codeborne:selenide:${selenideVersion}") {
exclude group: 'junit'
}
// Allure
agent 'org.aspectj:aspectjweaver:1.8.10'
compile 'ru.yandex.qatools.allure:allure-junit-adaptor:1.4.23'
compile 'io.qameta.allure:allure-junit5:2.0-BETA6'
}
junitPlatform {
platformVersion = "1.0.0-M5"
enableStandardTestTask = true
}
task runJupiter(type: JavaExec) {
jvmArgs '-ea'
jvmArgs "-javaagent:${configurations.agent.singleFile}"
classpath = project.sourceSets.test.runtimeClasspath
main 'org.junit.platform.console.ConsoleLauncher'
args '--scan-class-path'
args "--reports-dir=${buildDir}/allure-results"
finalizedBy 'allureReport'
}
test.dependsOn runJupiter
Tests are finished successfully and three folders are created automatically:
{projectDir}\allure-results with .json file
{projectDir}\build\test-results\junit-platform with TEST-junit-jupiter.xml file
{projectDir}\build\reports\allure-report
I tried to open .json and .xml result locally via allure command line (CLI). The allure report is opened but it is blank:
this is a report view
I suppose my mistake in gradle dependencies. I quite confused which libraries and versions should be used for JUnit5+Allure2+Gradle+Selenide+Java8?
The JUnit Platform Gradle plugin does currently not use the test task (it needs changes in Gradle core in order to do so). Thus, things like test.doFirst {...} are not going to work.
Instead of using the plugin, you should be able to create your own task that runs the ConsoleLauncher and add the JVM agent there. See https://stackoverflow.com/a/43512503/6327046 for an example.
I am having difficulty combining Jacoco coverage report for a Gradle multi-project. For simplicity, I have created a simplified version that is structured as follows. I have the example project on GitHub.
+ root
+ common-a
+ common-b
+ project-a
+ project-b
The root, project-a, and project-b are Spring Boot applications. For some context, a project is meant to be a micro-service. Thus, the root project is simply running all micro-services in one process.
Not all projects have unit and/or integration tests. common-a subproject does not have any tests; common-b, project-a, and project-b projects have unit and integration tests; the root project has only integration tests.
The Jacoco coverage reports for subprojects are correct. It is able to combine both unit and integration tests into one cohesive report. However, the root project does not produce the cohesive report correctly.
I have tried a number of solutions with any success. Most of the solutions I found assume that the root project is simply a logical container and only the subprojects has test code. The results of the solutions I tried fall into one of the following three categories.
No Jacoco report generated at all; the build/reports/jacoco directory is missing
Partial Jacoco report for only sources in root project
Full Jacoco coverage report for root and subproject but 0% coverage; it is supposed to be 100% coverage
The following is the current build.gradle file.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.3.5.RELEASE")
}
}
// settings for all projects
allprojects {
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'io.spring.dependency-management'
apply plugin: 'jacoco'
group 'io.github.chriszhong'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
repositories {
jcenter()
}
dependencyManagement {
imports {
mavenBom 'io.spring.platform:platform-bom:2.0.5.RELEASE'
}
}
sourceSets {
integrationTest {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
java {
srcDir 'src/test-integration/java'
}
resources {
srcDir 'src/test-integration/resources'
}
}
}
configurations {
integrationTestCompile {
extendsFrom testCompile
}
integrationTestRuntime {
extendsFrom testRuntime
}
}
idea {
module {
testSourceDirs += sourceSets.integrationTest.java.srcDirs
testSourceDirs += sourceSets.integrationTest.resources.srcDirs
}
}
task integrationTest(type: Test) {
check {
dependsOn integrationTest
}
testClassesDir sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
}
task testReport(type: TestReport) {
dependsOn check
destinationDir file("${reporting.baseDir}/unified/html")
reportOn test, integrationTest
}
task jacocoMerge(type: JacocoMerge) {
dependsOn check
executionData test, integrationTest
// temporary hack to fix a bug requiring that there be at least one test case in each source set for coverage data to be generated;
// it should be if there is at least one test case in any of the source sets
executionData = files(executionData.findAll({ it.exists() }))
}
tasks.withType(Test) {
reports {
html {
destination file("${reporting.baseDir}/${task.name}/html")
}
}
}
tasks.withType(JacocoReport) {
dependsOn jacocoMerge
executionData jacocoMerge.destinationFile
// temporary hack to fix a bug requiring that there be at least one test case in each source set for coverage data to be generated;
// it should be if there is at least one test case in any of the source sets
// executionData = files(executionData.findAll({ it.exists() }))
}
}
apply plugin: 'spring-boot'
version '1.0-SNAPSHOT'
dependencies {
compile project(':project-a')
compile project(':project-b')
testCompile 'junit:junit'
integrationTestCompile 'org.springframework.boot:spring-boot-starter-test'
}
testReport {
dependsOn check, subprojects.testReport
reportOn test, integrationTest, subprojects.test, subprojects.integrationTest
}
jacocoMerge {
dependsOn check, subprojects.jacocoMerge
executionData test, integrationTest, subprojects.jacocoMerge.destinationFile
// temporary hack to fix a bug requiring that there be at least one test case in each source set for coverage data to be generated;
// it should be if there is at least one test case in any of the source sets
executionData = files(executionData.findAll({ it.exists() }))
}
//jacocoTestReport {
// dependsOn jacocoMerge
// executionData test, integrationTest, subprojects.test, subprojects.integrationTest
// executionData jacocoMerge.destinationFile
// temporary hack to fix a bug requiring that there be at least one test case in each source set for coverage data to be generated;
// it should be if there is at least one test case in any of the source sets
// executionData = files(executionData.findAll({ it.exists() }))
// sourceDirectories = files(sourceSets.main.java.srcDirs, subprojects.sourceSets.main.java.srcDirs)
// classDirectories = files(sourceSets.main.output.classesDir, subprojects.sourceSets.main.output.classesDir)
//}
task wrapper(type: Wrapper) {
gradleVersion '2.14'
distributionUrl "https://services.gradle.org/distributions/gradle-${gradleVersion}-all.zip"
}
I have been banging my head at this problem for the past week and is at my wits end. I greatly appreciate any help I can get in resolving this problem.
I have tried to get code coverage in a spring-gradle project using gradle jacoco plugin.
The build.gradle contains the following
apply plugin: "jacoco"
jacoco {
toolVersion = "0.7.1.201405082137"
reportsDir = file("$buildDir/customJacocoReportDir")
}
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination "${buildDir}/jacocoHtml"
}
}
I then ran
gradle test jacocoTestReport
Where after only the file test.exec is generated in build/reports folder.
Other than that nothing happens.
How can I get the HTML report?
You don't have to configure reportsDir/destinationFile
Because jacoco has default values for them.
build.gradle:
plugins {
id 'java'
id 'jacoco'
}
jacocoTestReport {
reports {
xml.enabled true
html.enabled true
csv.enabled true
}
}
repositories {
jcenter()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
Run gradle test jacocoTestReport
You can find the test report in ./build/reports/jacoco/test directory.
HTML output is in ./build/reports/jacoco/test/html directory.
Following helped . its in samples/testing/jacaco of gradle-2.3-all.zip from https://gradle.org/releases/
apply plugin: "java"
apply plugin: "jacoco"
jacoco {
toolVersion = "0.7.1.201405082137"
reportsDir = file("$buildDir/customJacocoReportDir")
}
repositories {
mavenCentral()
}
dependencies {
testCompile "junit:junit:4.+"
}
test {
jacoco {
append = false
destinationFile = file("$buildDir/jacoco/jacocoTest.exec")
classDumpFile = file("$buildDir/jacoco/classpathdumps")
}
}
jacocoTestReport {
reports {
xml.enabled false
csv.enabled false
html.destination "${buildDir}/jacocoHtml"
}
}
Unfortunately, none of these answers worked for me.
I had a similar issue.
Only different in not having the exec file generated.
And because of that ,
I found that the jacocoTestReport was simply "skipped".
I got it fixed by adding :
apply plugin: 'jacoco'
test {
useJUnitPlatform()
finalizedBy jacocoTestReport // report is always generated after tests run
}
jacocoTestReport {
...
...
...
...
}
That's because I'm using Junit5 with spring boot 2.X
subprojects {
apply(plugin: 'org.jetbrains.kotlin.jvm')
repositories {
jcenter()
mavenCentral()
}
}
task codeCoverageReport(type: JacocoReport) {
// Gather execution data from all subprojects
executionData fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec")
// Add all relevant sourcesets from the subprojects
subprojects.each {
sourceSets it.sourceSets.main
}
reports {
xml.enabled true
html.enabled true
csv.enabled false
}
}
// always run the tests before generating the report
codeCoverageReport.dependsOn {
subprojects*.test
}
sonarqube {
properties {
property "sonar.projectKey", "your_project_key"
property "sonar.verbose", true
property "sonar.projectName", "Your project name"
property "sonar.coverage.jacoco.xmlReportPaths", "${rootDir}/build/reports/jacoco/codeCoverageReport/codeCoverageReport.xml"
}
}
Command to run test with coverage:
./gradlew codeCoverageReport
./gradlew sonarqube -x test (test is excluded since already run and sonarqube by default executes test)
The second command can be ignored if sonarqube is not being used.
Two things to be noted that made it work:
To make available sourcesets of all modules, looping over subprojects and accumulating sourcesets worked. subprojects.sourceSets.main.allSource.srcDirs did not work.
sonar.jacoco.reportPaths is deprecated. We need to use sonar.coverage.jacoco.xmlReportPaths. Check the documentation here
I was hoping to bring querydsl into my spring-boot project via gradle. Despite finding a couple of examples online, none of them actually work for me because of issues with dependencies (I think). According to the QueryDSL support forum, gradle is not supported yet. But I was wondering with all the gradle & spring-boot being created if someone has managed to make it work yet?
Here is my build.gradle:
apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'idea'
apply plugin: 'spring-boot'
apply plugin: 'jacoco'
apply plugin: 'war'
buildscript {
repositories {
maven { url "http://repo.spring.io/libs-snapshot" }
mavenLocal()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.0.0.RC4")
}
}
repositories {
mavenCentral()
maven { url: "http://repo.spring.io/libs-snapshot" }
// maven { url: "http://repo.spring.io/milestone" }
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:1.0.0.RC5")
compile("org.springframework.boot:spring-boot-starter-data-jpa:1.0.0.RC5")
compile("org.springframework:spring-orm:4.0.0.RC1")
compile("org.hibernate:hibernate-entitymanager:4.2.1.Final")
compile("com.h2database:h2:1.3.172")
compile("joda-time:joda-time:2.3")
compile("org.thymeleaf:thymeleaf-spring4")
compile("org.codehaus.groovy.modules.http-builder:http-builder:0.7.1")
compile('org.codehaus.groovy:groovy-all:2.2.1')
compile('org.jadira.usertype:usertype.jodatime:2.0.1')
// this line fails
querydslapt "com.mysema.querydsl:querydsl-apt:3.3.2"
testCompile('org.spockframework:spock-core:0.7-groovy-2.0') {
exclude group: 'org.codehaus.groovy', module: 'groovy-all'
}
testCompile('org.codehaus.groovy.modules.http-builder:http-builder:0.7+')
testCompile("junit:junit")
}
jacocoTestReport {
group = "Reporting"
description = "Generate Jacoco coverage reports after running tests."
}
task wrapper(type: Wrapper) {
gradleVersion = '1.11'
}
sourceSets {
main {
generated {
java {
srcDirs = ['src/main/generated']
}
}
java {
srcDirs = []
}
groovy {
srcDirs = ['src/main/groovy', 'src/main/java']
}
resources {
srcDirs = ['src/main/resources']
}
output.resourcesDir = "build/classes/main"
}
test {
java {
srcDirs = []
}
groovy {
srcDirs = ['src/test/groovy', 'src/test/java']
}
resources {
srcDirs = ['src/test/resources']
}
output.resourcesDir = "build/classes/test"
}
}
configurations {
// not really sure what this is, I see it in examples but not in documentation
querydslapt
}
task generateQueryDSL(type: JavaCompile, group: 'build', description: 'Generates the QueryDSL query types') {
source = sourceSets.main.java
classpath = configurations.compile + configurations.querydslapt
options.compilerArgs = [
"-proc:only",
"-processor", "com.mysema.query.apt.jpa.JPAAnnotationProcessor"
]
destinationDir = sourceSets.generated.java.srcDirs.iterator().next()
}
compileJava {
dependsOn generateQueryDSL
source generateQueryDSL.destinationDir
}
compileGeneratedJava {
dependsOn generateQueryDSL
options.warnings = false
classpath += sourceSets.main.runtimeClasspath
}
clean {
delete sourceSets.generated.java.srcDirs
}
idea {
module {
sourceDirs += file('src/main/generated')
}
}
But gradle fails with:
Could not find method querydslapt() for arguments [com.mysema.querydsl:querydsl-apt:3.3.2]
I have tried changing the querydsl-apt version to earlier ones but I get the same error.
Working configuration for Spring Boot 1.3.5 and supported QueryDSL, tested with gradle 2.14.
ext {
queryDslVersion = '3.6.3'
javaGeneratedSources = file("$buildDir/generated-sources/java")
}
compileJava {
doFirst {
javaGeneratedSources.mkdirs()
}
options.compilerArgs += [
'-parameters', '-s', javaGeneratedSources
]
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile "com.mysema.querydsl:querydsl-jpa:$queryDslVersion"
compileOnly "com.mysema.querydsl:querydsl-apt:$queryDslVersion:jpa"
}
Complete project source code: spring-boot-querydsl
You probably need to do at least 2 things:
Declare the "querydslapt" configuration before you use it
Add querydsl-jpa (or whatever flavours you need) to your "compile" configuration.
Then you will have the classpath set up, but the apt bit will not do anything without some more configuration (as you found no doubt from the querydsl support forum). The apt but is used to generate some code that you then need to compile and use in your application code (the "Q*" classes corresponding to your domain objects). You could drive that from a build task in gradle I imagine (it only has to run once for every change in the domain objects).