Cobertura not generating coverage report - gradle

I am trying to use cobertura to generate coverage report for my groovy project. I am using gradle to install cobertura ang junit 5
plugins {
id 'java'
id 'groovy'
id 'net.saliman.cobertura' version '2.5.4'
}
dependencies {
implementation 'org.codehaus.groovy:groovy-all:2.4.0'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1'
}
test {
useJUnitPlatform()
}
Running the cobertura task generates an empty coverage report (0 classes and no coverage). The jUnit report shows the correct unit test which have been run.
Gralde output
> Task :coberturaReport UP-TO-DATE
> Task :compileJava NO-SOURCE
> Task :compileGroovy
> Task :processResources NO-SOURCE
> Task :classes
> Task :instrument
Cobertura 2.1.1 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
> Task :copyCoberturaDatafile
> Task :compileTestJava NO-SOURCE
> Task :compileTestGroovy
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :test
> Task :generateCoberturaReport
Cobertura 2.1.1 - GNU GPL License (NO WARRANTY) - See COPYRIGHT file
Report time: 150ms
> Task :performCoverageCheck SKIPPED
> Task :cobertura
BUILD SUCCESSFUL in 11s
6 actionable tasks: 6 executed
07:53:16: Task execution finished 'cobertura'.
What confuses me is the line > Task :performCoverageCheck SKIPPED Is this the problem? How do I enable the coverage check?

After enabling --debug, I found that it is not instrumenting any classes. Adding coverageDirs = ["${buildDir}/classes/groovy/main"] in cobertura as below solved the issues for me.
cobertura {
coverageFormats = ["html", "xml"]
coverageIgnoreTrivial true
coverageCheckHaltOnFailure false
coverageDirs = ["${buildDir}/classes/groovy/main"]
}

Related

Ignore file when calculating gradle cache fingerprint

In my project I access the build-info.properties generated by the gradle springboot plugin buildInfo() task during runtime to include my project version in log metadata.
My problem is that this file is included in the fingerprint calculation for gradle tasks such as tests via the classpath fingerprint, but the version in that file changes with every build in my pipelines. Therefore I can never reuse that cache.
I saw this question on how to exclude that file from runtime, but if I follow that advise,
the file's not available during runtime anymore, naturally.
the file /BOOT-INF/classes/META-INF/build-info.properties is empty. Therefore my application fails on startup.
Can I somehow exclude it from the cache fingerprint calculation only?
Edits:
I'm currently on Gradle 6.8.1 and Spring Bot 2.2.2.
This is how I generate the file:
springBoot {
buildInfo()
}
And this is how I add the normalization:
normalization {
runtimeClasspath {
ignore "**/build-info.properties"
}
}
Update: As stated in the comment, this problem appeared due to a missconfiguration of my Gradle build scripts in another location. The normalization approach linked in the question and explained in the accepted answer is the solution to the initial question.
Gradle input normalization should be a solution for it.
normalization {
runtimeClasspath {
ignore '**/build-info.properties'
}
}
Not sure why you are saying " if I follow that advise, the file's not available during runtime anymore". According to documentation
The effect of this configuration would be that changes to build-info.properties would be ignored for up-to-date checks and build cache key calculations. Note that this will not change the runtime behavior of the test task — i.e. any test is still able to load build-info.properties and the runtime classpath is still the same as before.
Here are some tests that proves the above
Running build first time
./gradlew build -Pversion=0.0.1 --console=plain
> Task :bootBuildInfo
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes
> Task :resolveMainClassName
> Task :bootJar
> Task :jar
> Task :assemble
> Task :compileTestJava UP-TO-DATE
> Task :processTestResources UP-TO-DATE
> Task :testClasses UP-TO-DATE
> Task :test
> Task :check
> Task :build
test task was executed because there is no build cache.
Running build second time with different version
./gradlew build -Pversion=0.0.2 --console=plain
> Task :bootBuildInfo
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes
> Task :resolveMainClassName UP-TO-DATE
> Task :bootJar
> Task :jar
> Task :assemble
> Task :compileTestJava UP-TO-DATE
> Task :processTestResources UP-TO-DATE
> Task :testClasses UP-TO-DATE
> Task :test UP-TO-DATE
> Task :check UP-TO-DATE
> Task :build
As you may see only build tasks were executed but test task is still UP-TO-DATE.
build-info.properties is still available under build/resources/main/META-INF/
build.artifact=demo
build.group=com.example
build.name=demo
build.time=2023-02-01T18\:32\:03.871040Z
build.version=0.0.2
and could be accessed using Spring Boot actuator endpoint /actuator/info in case it's enabled
{
"build": {
"artifact": "demo",
"name": "demo",
"version": "0.0.2",
"group": "com.example"
}
}
Consider excluding build time
You could optimize even more by excluding time from the build info.
springBoot {
buildInfo {
excludes = ['time']
}
}
Usually it's a good idea for optimizing local builds. Otherwise build tasks will be always executed. By excluding time all tasks will be cached
./gradlew build --console=plain
> Task :bootBuildInfo UP-TO-DATE
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :resolveMainClassName UP-TO-DATE
> Task :bootJar UP-TO-DATE
> Task :jar UP-TO-DATE
> Task :assemble UP-TO-DATE
> Task :compileTestJava UP-TO-DATE
> Task :processTestResources UP-TO-DATE
> Task :testClasses UP-TO-DATE
> Task :test UP-TO-DATE
> Task :check UP-TO-DATE
> Task :build UP-TO-DATE
but build.time will not be part of the build-info.properties
build.artifact=demo
build.group=com.example
build.name=demo
build.version=0.0.1-SNAPSHOT

Publishing artifact only after tests were successful

I've been fighting this problem for a long time and genuinely out of ideas. In my project I use the maven-publish plugin for publishing artifact to my repository:
plugins {
kotlin("jvm") version "1.6.20"
id("maven-publish")
}
And also using Kotest to run tests:
tasks.withType<Test> {
useJUnitPlatform()
}
Obviously, I want to publish artifacts only if all tests passed, so I add the following:
tasks.publish {
dependsOn(tasks.test)
mustRunAfter(tasks.test)
}
However, when I run ./gradlew clean build test publish on the command line, the artifacts are always published before the tests run:
> Task :clean
> Task :processResources NO-SOURCE
> Task :processTestResources
> Task :generatePomFileFor«project-name»Publication
> Task :compileKotlin
> Task :compileJava NO-SOURCE
> Task :classes UP-TO-DATE
> Task :inspectClassesForKotlinIC
> Task :jar
> Task :assemble
> Task :generateMetadataFileFor«project-name»Publication
> Task :publish«project-name»PublicationTo«repository-name»Repository
> Task :compileTestKotlin
> Task :compileTestJava NO-SOURCE
> Task :testClasses
> Task :test
Is there something I'm missing?
Took me long enough. Apparently, the publish task is not the one that actually publishes the jar, but the publish«project-name»PublicationTo«repository-name»Repository. However, this task is not available until after configuration, so the best I could do is:
afterEvaluate {
tasks.getByName("publish«project-name»PublicationTo«repository-name»Repository").dependsOn(tasks.test)
}

Cannot run cucumber JUnit tests on Gradle

I am trying to run a Cucumber / Selenium project using IntelliJ Community edition and Gradle 5.5.1.
My folder structure is as follows:
ProjectRoot
|
src---main---java
|
src---test---java---packagename---stepdefinitions---Steps.java
|
-----resources---feature---application.feature
My TestRunner class is as follows:
#RunWith(Cucumber.class)
#CucumberOptions(
plugin = {"pretty", "json:cucumber-report.json"},
features = {"src/test/resources/feature"})
public class TestRunner {
}
When I try to run the TestRunner what I get is the following:
Testing started at 18:48 ...
> Task :cleanTest
> Task :compileJava UP-TO-DATE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :compileTestJava
> Task :processTestResources UP-TO-DATE
> Task :testClasses
> Task :test FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':test'.
> No tests found for given includes: [org.fifthgen.scanmaltatesting.TestRunner](filter.includeTestsMatching)
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 1s
5 actionable tasks: 3 executed, 2 up-to-date
This is my build.gradle:
plugins {
id 'java'
}
group 'org.fifthgen'
version '1'
sourceCompatibility = 11
targetCompatibility = 11
repositories {
mavenCentral()
}
wrapper.gradleVersion = '5.5.1'
def cucumberVersion = '4.7.2'
def junitVersion = '5.5.2'
dependencies {
implementation 'org.seleniumhq.selenium:selenium-java:3.141.59'
testImplementation "io.cucumber:cucumber-java:${cucumberVersion}"
testImplementation "io.cucumber:cucumber-junit:${cucumberVersion}"
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitVersion}"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitVersion}"
}
test {
useJUnitPlatform()
scanForTestClasses = false
}
When I run the test task using Gradle, I get
BUILD SUCCESSFUL in 0s
4 actionable tasks: 1 executed, 3 up-to-date
18:52:41: Task execution finished 'test'.
Without the Cucumber scenarios being run.
ˋRunWithˋ is a JUnit 4 mechanism. In order to use that with JUnit 5 platform mechanism you must include dependency on junit-vintage engine which allows running JUnit 4 tests on JUnit 5.
Alternatively you could change to the Cucumber engine for JUnit 5. I’m not sure though if it has already been released.
From the docs,
Cucumber is based on JUnit 4. If you’re using JUnit 5, remember to include junit-vintage-engine dependency, as well. For more information, please refer to JUnit 5 documentation.
Adding following dependencies made it work on IntelliJ:
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.7.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.7.2")
testRuntimeOnly("org.junit.vintage:junit-vintage-engine:5.7.2")
Check here for more details

Trying to run Spock Specification using Gradle... "Test Events were not received" (In IntelliJ Idea)

I am trying to run a simple Spock specification with Groovy, in a Gradle project. But I am getting this message Test events were not received.
Here is my build.gradle:
plugins {
id 'groovy'
}
group 'com.Sample'
version '1.0-SNAPSHOT'
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'groovy'
repositories {
mavenCentral()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.3.11'
testCompile "org.spockframework:spock-core:1.1-groovy-2.4"
}
Here is my spock specification :
import spock.lang.Specification
class SampleSpec extends Specification {
def "validate string concat"(){
given:
def string1 = "hello"
def string2 = "world"
when:
def stringConcat = string1.concat(string2)
then:
stringConcat == "helloworld"
}
}
Here is the message I get when I run the Spock Specification:
> Task :cleanTest UP-TO-DATE
> Task :compileJava UP-TO-DATE
> Task :compileGroovy NO-SOURCE
> Task :processResources NO-SOURCE
> Task :classes UP-TO-DATE
> Task :compileTestJava NO-SOURCE
> Task :compileTestGroovy NO-SOURCE
> Task :processTestResources NO-SOURCE
> Task :testClasses UP-TO-DATE
> Task :test NO-SOURCE
BUILD SUCCESSFUL in 0s
2 actionable tasks: 2 up-to-date
9:20:33 AM: Tasks execution finished ':cleanTest :test --tests "SampleSpec.validate string concat"'.
Any help would be greatly appreciated!
EDIT:
Now my Spock tests are running successfully but I am getting this message:
WARNING: Illegal reflective access by org.codehaus.groovy.reflection.CachedClass (file:/C:/Users/dtara/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy-all/2.4.9/3334e99a8baae12d6e014d444149e337ceb99a00/groovy-all-2.4.9.jar) to method java.lang.Object.finalize()
WARNING: Please consider reporting this to the maintainers of org.codehaus.groovy.reflection.CachedClass
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
**Anyone knows that this means? Should I worry about it? **
Ok, first question:
The tests should live in src/test/groovy not src/test/java (and packages would be nice) ;-)
Second question:
You're using quite an old version of Groovy, but until Groovy 3.0 comes out, you'll see that warning when using Java 9+. It's trying to use things in Java that Java is going to remove in a future release...
It's fine to run with what you have at the moment (apart from maybe pull in the latest groovy -- 2.5.8 at the time I'm writing this)

Is there a way to have Gradle call flywayMigrate on build?

I'd find it really useful to invoke Flyway's migrate command automatically each time I run gradle build.
Spring Boot does this under the hood, but can Gradle do this itself? I have a non-Boot app that I'd like to be able to manage the same way.
I'm hoping it is some lifecycle hook. This question is helpful, but how do I execute flyway pre-build?
Yes you can. You have several options. You can hook into the lifecycle at any point. By default the java gradle plugin has several places you could hook into.
$ ./gradlew clean build
:clean
:compileJava
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
:check
:build
You can attach to any of these points
Or you if you need to be applied no matter what before anything else then you might want to consider a simple plugin.
Here is an example of both:
build.gradle:
apply plugin: 'java'
repositories {
jcenter()
}
dependencies {
testCompile 'junit:junit:4.12'
}
task runFlyAwayCommand << {
// process is type java.lang.Process
def process = "printf lifecycle hooked task".execute()
def processExitValue = process.waitFor()
def processOutput = process.text
project.logger.lifecycle("Flyaway{ exitValue: $processExitValue output: $processOutput }")
}
// compileJava could be any lifecycle task
tasks.findByName('compileJava').dependsOn tasks.findByName('runFlyAwayCommand')
// if you need to execute earlier you might want to create a plugin
apply plugin: SamplePlugin
class SamplePlugin implements Plugin<Project> {
#Override
void apply(Project project) {
def process = "printf plugin apply".execute()
def processExitValue = process.waitFor()
def processOutput = process.text
project.logger.lifecycle("Flyaway{ exitValue: $processExitValue output: $processOutput }")
}
}
Output:
$ ./gradlew clean build
Configuration on demand is an incubating feature.
Flyaway{ exitValue: 1 output: plugin }
:clean
:runFlyAwayCommand
Flyaway{ exitValue: 1 output: lifecycle }
:compileJava
:processResources UP-TO-DATE
:classes
:jar
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
:check
:build
BUILD SUCCESSFUL
Total time: 1.294 secs

Resources