How to create a Gradle Task to run only a specific Tests in Spring - spring

I have a Spring Project where I wrote some Unit and Integration Tests. Now I want to create custom tasks for running all unit tests, all integration tests and one task for running both. But how can I do this?

I would suggest separating integration tests into separate source set. By default you already have 2 source sets, one for production code and one for tests. To create a new source set (create new directory under src/integrationTest/java) and add a following configuration using Junit5:
test {
useJUnitPlatform()
}
sourceSets {
integrationTest {
java.srcDir file("src/integrationTest/java")
resources.srcDir file("src/integrationTest/resources")
compileClasspath += sourceSets.main.output + configurations.testRuntime
runtimeClasspath += output + compileClasspath
}
}
For separate task:
task integrationTest(type: Test) {
description = 'Runs the integration tests.'
group = 'verification'
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
useJUnitPlatform()
reports {
html.enabled true
junitXml.enabled = true
}
}
Now you have 3 tasks available:
gradlew test
gradlew integrationTest
gradlew check - runs both as it depends on Test task which both extend
If you also are using jacoco and want to merge the test results then you can have following tasks:
task coverageMerge(type: JacocoMerge) {
destinationFile file("${rootProject.buildDir}/jacoco/test.exec")
executionData fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec")
}
// aggregate all coverage data at root level
if (tasks.findByName("test")) {
tasks.findByName("test").finalizedBy coverageMerge
}
if (tasks.findByName("integrationTest")) {
tasks.findByName("integrationTest").finalizedBy coverageMerge
}
task codeCoverageReport(type: JacocoReport) {
executionData fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec")
subprojects.each {
if (!it.name.contains('generated')) {
sourceSets it.sourceSets.main
}
}
reports {
xml.enabled true
html.enabled true
html.setDestination(new File("${buildDir}/reports/jacoco"))
csv.enabled false
}
}
To run coverage report just execute
gradlew codeCoverageReport

Related

jacocoTestReport always SKIPPED

Expected Behavior
jacocoTestReport work
Current Behavior
jacocoTestReport SKIPPED
Context
I created a task whose type is Test, and jacocoTestReport depends on the task. When I ran the task, jacocoTestReport did not work and I got the following information
jacocoTestReport SKIPPED
I find if I use the task test directly, jacocoTestReport worked fine. It makes me confused
the following code caused the above issue
plugins {
id 'java'
id 'jacoco'
}
repositories {
mavenCentral()
}
dependencies {
}
task myTest(type: Test) {
useTestNG()
useJUnitPlatform()
finalizedBy jacocoTestReport
reports {
junitXml.required = false
html.required = true
}
jacoco {
enabled = true
destinationFile = layout.buildDirectory.file("jacoco/${name}.exec").get().asFile
}
}
jacocoTestReport {
// tests are required to run before generating the report
dependsOn myTest
reports {
xml.required = false
csv.required = false
html.outputLocation = layout.buildDirectory.dir('jacocoHtml')
}
}
Steps to Reproduce
example project
Your Environment
Gradle 7.1.1
It is expected, not an issue. just because I use the jacocoTestReport in a wrong way
see https://github.com/gradle/gradle/issues/18271

Include multiple sourcesets in the Jacoco's jacocoTestReport.xml file

I have a custom sourceSet defined in a Gradle based project, like this:
sourceSets {
componentTest {
java {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
srcDir file('src/componentTest/java')
}
}
}
configurations {
componentTestImplementation.extendsFrom testImplementation
}
task componentTest(type: Test) {
dependsOn assemble
testClassesDirs = sourceSets.componentTest.output.classesDirs
classpath = sourceSets.componentTest.runtimeClasspath
outputs.upToDateWhen { false }
testLogging.showStandardStreams = true
mustRunAfter(test)
}
check.dependsOn(componentTest)
The sourceSet contains Cucumber features.
When running Jacoco, the generated jacocoTestReport.xml file doesn't seem to include the coverage generated by the Cucumber tests.
Here is the Jacoco configuration:
jacocoTestReport {
executionData(
file("${project.buildDir}/jacoco/test.exec"),
file("${project.buildDir}/jacoco/componentTest.exec"),
)
}
Is there anything I could do to get the same coverage in the xml file as I get in the exec files?
After further experiments it turns out the xml file includes the coverage from the componentTest sourceSet.
I asked this question because the coverage was not reflected correctly in SonarQube - I could not see the Cucumber tests from the componentTest in SonarQube. But it seems to me now, that the actual coverage values align with what the Jacoco report shows. I just had to exclude the same source classes in SonarQube as in Jacoco.

jacocoTest exclusion has no effect

I have a gradle project and I want to exclude some directories from TC coverage. This is what I am giving in the task
jacocoTestReport {
reports {
xml.enabled true
csv.enabled false
html.enabled true
}
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it).exclude(
// define here
'com/this/that'
)
}))
}
}
However the classes still shows up in the coverage.
What am I missing?
afterEvaluate runs in Gradle's configuration phase which is before any tasks have executed and before any classes have been compiled (see build phases)
I'm guessing you want something like
test {
jacoco {
excludes = ['com/this/that/*']
}
}

Spring cloud contracts plugin change sourceset

I've started using Spring Cloud Contracts ('2.0.2.RELEASE') in my project and I have the following structure
src
|
-- main
-- test
-- integrationTest
-- contractTest
When I put my contracts and my base test class in test it was running fine. I want to move the contract tests that I have written into a separate sourceset, the contractTest sources. However, this will not work as the plugin generateContractTests task will still look in the test sourceset when trying to run.
I have made the following changes to my Gradle file
task contractTest(type: Test) {
description = 'Runs contract tests.'
group = 'verification'
testClassesDirs = sourceSets.contractTest.output.classesDirs
classpath = sourceSets.contractTest.runtimeClasspath
shouldRunAfter integrationTest
}
configurations {
contractTestImplementation.extendsFrom implementation
contractTestRuntimeOnly.extendsFrom runtimeOnly
}
sourceSets {
contractTest {
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
}
}
contracts {
// testFramework = 'JUNIT5'
packageWithBaseClasses = 'com.test.testapi.contracts'
contractsDslDir = new File("${project.rootDir}/src/contractTest/resources/contracts/")
}
contractTestImplementation 'org.codehaus.groovy:groovy-all:2.4.6'
contractTestImplementation 'org.springframework.cloud:spring-cloud-starter-contract-verifier'
contractTestImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api'
contractTestImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-engine'
I think I need to set the contract plugin property contractDependency, however, I am not sure and can't find an example to get the plugin to work with this different sourceset
TLDR; I want to be able to run my contract tests in a different folder
UPDATE - I am not sure but I think that it is not possible as in the Gradle plugin in the "GenerateServerTestsTask.groovy" file has the following which would appear to signify that the sourceSet is hardcoded to test throughout the code
project.sourceSets.test.groovy {
project.logger.
info("Registering ${getConfigProperties().generatedTestSourcesDir} as test source directory")
srcDir getConfigProperties().getGeneratedTestSourcesDir()
}
For future reference, I was able to get it working by creating a custom task to deregister the generated sources from the test sourceset so that they wouldn't be compiled by compileTestJava and could be run via my own contractTests task.
sourceSets {
contractTest {
java {
compileClasspath += sourceSets.main.output + sourceSets.test.output
runtimeClasspath += sourceSets.main.output + sourceSets.test.output
srcDir file('src/contractTest/java')
srcDirs += file("${buildDir}/generated-contract-sources/")
}
resources.srcDir file('src/contractTest/resources')
}
}
task deregisterContractTestSources() {
doLast {
project.sourceSets.test.java {
project.logger.info('Removing any *Spec classes from the test sources')
exclude '**/*Spec*'
}
}
}
compileTestJava.dependsOn deregisterContractTestSources
task contractTests(type: Test) {
description = 'Runs contract tests'
group = 'verification'
testClassesDirs = sourceSets.contractTest.output.classesDirs
classpath = sourceSets.contractTest.runtimeClasspath
}
contracts {
baseClassForTests = 'com'
generatedTestSourcesDir = file("${buildDir}/generated-contract-sources")
generatedTestResourcesDir = file("${buildDir}/generated-contract-resources/")
testFramework = "JUNIT5"
contractsDslDir = new File("${projectDir}/src/contractTest/resources/contracts/")
nameSuffixForTests = 'Spec'
basePackageForTests = 'com'
}

Running specific tests using gradle over multiple browsers

I'm using Geb/Spock for automated testing. I'm using Gradle as my build tool.
I'd like to call different gradle tasks to build and run a specific spec(test) or a suite of specs.
I dont know enough about the gradle build lifecycle to completely understand what is going on here: https://github.com/geb/geb-example-gradle/blob/master/build.gradle
plugins {
id "idea"
id "groovy"
id "com.energizedwork.webdriver-binaries" version "1.4"
id "com.energizedwork.idea-base" version "1.4"
}
ext {
// The drivers we want to use
drivers = ["firefox", "chrome", "chromeHeadless"]
ext {
groovyVersion = '2.4.12'
gebVersion = '2.2'
seleniumVersion = '3.6.0'
chromeDriverVersion = '2.32'
geckoDriverVersion = '0.18.0'
}
}
repositories {
mavenCentral()
}
dependencies {
// If using Spock, need to depend on geb-spock
testCompile "org.gebish:geb-spock:$gebVersion"
testCompile("org.spockframework:spock-core:1.1-groovy-2.4") {
exclude group: "org.codehaus.groovy"
}
testCompile "org.codehaus.groovy:groovy-all:$groovyVersion"
// If using JUnit, need to depend on geb-junit (3 or 4)
testCompile "org.gebish:geb-junit4:$gebVersion"
// Drivers
testCompile "org.seleniumhq.selenium:selenium-chrome-driver:$seleniumVersion"
testCompile "org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion"
}
webdriverBinaries {
chromedriver chromeDriverVersion
geckodriver geckoDriverVersion
}
drivers.each { driver ->
task "${driver}Test"(type: Test) {
group JavaBasePlugin.VERIFICATION_GROUP
outputs.upToDateWhen { false } // Always run tests
systemProperty "geb.build.reportsDir", reporting.file("geb/$name")
systemProperty "geb.env", driver
}
}
test {
dependsOn drivers.collect { tasks["${it}Test"] }
enabled = false
}
tasks.withType(Test) {
maxHeapSize = "1g"
jvmArgs '-XX:MaxMetaspaceSize=128m'
testLogging {
exceptionFormat = 'full'
}
}
tasks.withType(GroovyCompile) {
groovyOptions.forkOptions.memoryMaximumSize = '256m'
}
I've tried inserting the following into build.gradle:
task dataGen {
include '**com.company.project.spec.util/DataGenerationUtilSpec.groovy'
}
task sanity {
include '**com.company.project.spec.sanity.*'
}
But calling these tasks (gradle sanity) results in a build failure:
Could not find method include() for arguments [**com.company.project.spec.util/DataGenerationUtilSpec.groovy] on task ':dataGen' of type org.gradle.api.DefaultTask
Obviously there's existing build instructions since I can call gradle build and all the specs run on Chrome, I'm just not sure how to add more tasks
I think these 2 tasks are test tasks so it should look like that :
task dataGen (type: Test) {
include '**com.company.project.spec.util/DataGenerationUtilSpec.groovy'
}
task sanity (type: Test) {
include '**com.company.project.spec.sanity.*'
}
You can use Spock annotation to control the test or the Spec, see example here.
You will have to define annotation classes and define the Spock config file to use that annotation. You then annotate the specific Specification (or test).
Now you will have to define the Spock config file in the task or from a parameter.

Resources