I have very successfully integrated Gradle (1.11), Sonar ( 4.1.1 ), Java, Scala and Jacoco in my build process. I even managed to get info regarding the number of successful tests ( thanks to Stackoverflow! ). I have one problem though.
I can't seem to get info about coverage per test. It would be very nice to have this info.
> 15:11:16.514 INFO - Sensor JaCoCoSensor... 15:11:16.535 INFO -
> Analysing C:\example\gradle-sonar-jacoco-scala\build\jacoco\test.exec
> 15:11:17.887 INFO - No information about coverage per test.
A simplified version of the project is at : https://github.com/sebastianharko/gradle-sonar-java-jacoco-scalatest-junit
Cheers !
It Looks like you already have
apply plugin: 'jacoco'
in your gradle.build
But i'm not seeing a definition to where it's to get it file from in the gradle.build
jacoco {
destinationFile = file("$buildDir/jacoco/test.exec")
}
If you plan on doing integration and unit testing it would look similar to the following:
task "integtest"(type: Test, dependsOn: integtestClasses) {
testClassesDir = sourceSets.integtest.output.classesDir
classpath = sourceSets.integtest.runtimeClasspath
jacoco {
destinationFile = file("$buildDir/jacoco/integTest.exec")
}
}
test {
jacoco {
destinationFile = file("$buildDir/jacoco/test.exec")
}
}
With the corresponding sonar configuration items
property "sonar.jacoco.reportPath", "$buildDir/jacoco/test.exec"
property "sonar.jacoco.itReportPath", "$buildDir/jacoco/integTest.exec"
I've seen another conf parameters from SonarQube - integrationTest.exec - sonarRunner (Gradle) or "sonar-runner" command - showing 0.0% covereage :
The parameter sonar.java.coveragePlugin=jacoco called my attention. Did you try that?
You may also want to use Coveralls.io
It's very cheap: only $4.99/mo. and you would have a deep integration with your pull requests on Github (track when a branch increases or decreases your code coverage) as well as a very nice UI to drill down into your code coverage.
Both SBT and Gradle integrations are available.
Related
I am trying to update a gradle 6.x version multi project application to gradle 7.3 as it is the first version to support Java 17. However, I am unable to progress past an issue arising from a task which is not declared in any of my build.gradle files. The error is below: ([] pieces are redacted)
Execution failed for task ':[root module]:[module]:processIntTestResources'.
> Entry [filename] is a duplicate but no duplicate handling strategy has been set. Please refer to https://docs.gradle.org/7.3/dsl/org.gradle.api.tasks.Copy.html#org.gradle.api.tasks.Copy:duplicatesStrategy for details.
I think is associated with a sourceSet for integration tests, however, I never explicitly copy and files for those tests. I have also set all copy instructions to have this configuration with regard to duplicate handling:
duplicatesStrategy = DuplicatesStrategy.INCLUDE
I also tried adding the above to projects which failed because that setting is only valid for Copy type tasks or blocks. I am by no means an expert in gradle and can add any relevant information needed, but I believe I have included what might be most relevant. I am really just looking for a direction I can head in to further debug this issue.
You didn't show much about how you have integration tests configured, but I ran into a similar problem. What saved me was this blog post by Tom Gregory:
Running integration tests in Gradle
Since links can disappear, let me copy and paste the most important part that I found relevant, which is regarding the new (as of Gradle 7.3) JVM Test Suite Plugin that adds support for integration tests. For me, this replaced my old integration test configuration:
testing {
suites {
integrationTest(JvmTestSuite) {
dependencies {
implementation project
}
}
}
}
tasks.named('check') {
dependsOn testing.suites.integrationTest
}
I also found the following useful, which is not in the above blog post, but is a leftover from my previous Gradle 6 configuration. This for me duplicates the 'test' dependencies for 'integrationTest'. This is not the recommended way of handling the test depedencies now (see the JVM Test Suite Plugin documentation), but I still found it useful to get me back running quickly:
configurations {
integrationTestImplementation.extendsFrom testImplementation
integrationTestRuntime.extendsFrom testRuntime
}
I could not find out how to set system properties when executing JUnit 5 tests using Gradle. The standard test task could be configured as follows:
test {
systemProperty 'org.slf4j.simpleLogger.defaultLogLevel', 'warn'
}
However, the junitPlatform task seem to not have such an option.
Update:
Please note that the junit-platform-gradle-plugin developed by the JUnit Team was deprecated in JUnit Platform 1.2 and discontinued in 1.3. Please switch to Gradle’s standard test task in Gradle 4.6 or higher. Details here.
As I mentioned here, if you are still using the obsolete junit-platform-gradle-plugin you can set system properties like this:
afterEvaluate {
def junitPlatformTestTask = tasks.getByName('junitPlatformTest')
junitPlatformTestTask.systemProperty 'org.slf4j.simpleLogger.defaultLogLevel', 'warn'
}
I'm using jacoco for code coverage. It runs (./gradlew createDebugCoverageReport) fine and generates code coverage for all the androidTest cases. However, it doesn't run the local unit tests, and hence doesn't compute the code coverage by these tests. How can I achieve all test cases including local to run and code coverage for all. I'm not sure what I'm missing. Any pointers will be great.
I can successfully run all the local unit tests on JVM with ./gradlew testDebugUnitTest
Please let me know if any more information is required.
An updated answer for Android Studio Chipmunk and Gradle 7.3.3
This is in the project level gradle
buildscript {
dependencies {
classpath 'org.jacoco:org.jacoco.core:0.8.7'
}
}
These are in the module level gradle
plugins {
id 'jacoco'
}
android {
buildTypes {
debug {
testCoverageEnabled true
}
}
tasks.withType(Test) {
jacoco {
includeNoLocationClasses = true
excludes = ['jdk.internal.*']
}
}
}
And finally, the task that runs the tests.
task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {
reports {
xml.getRequired().set(true)
html.getRequired().set(true)
}
def fileFilter = [
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
'android/**/*.*'
]
def debugTree = fileTree(
dir: "$project.buildDir/tmp/kotlin-classes/debug",
excludes: fileFilter
)
def mainSrc = "$project.projectDir/src/main/java"
sourceDirectories.from(files([mainSrc]))
classDirectories.from(files([debugTree]))
executionData.from(fileTree(
dir: "$buildDir",
includes: [
"outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec",
"outputs/code_coverage/debugAndroidTest/connected/*/coverage.ec"
]
))
}
"$project.buildDir/tmp/kotlin-classes/debug" is for Kotlin. Change to "$project.buildDir/intermediates/classes/debug" for Java.
testDebugUnitTest runs unit tests and creates a coverage report at "outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec".
Note that path may differ. I searched for "exec" in the app folder to find it.
createDebugCoverageReport runs the Android tests and creates a coverage report at "outputs/code_coverage/debugAndroidTest/connected/*/coverage.ec". Note that this path may also differ. I searched for "coverage.ec" in the app folder to find it.
Finally, to run the tests and create a coverage report you can create a run configuration to run "clean jacocoTestReport" or tap ctrl twice in Android Studio and run "./gradlew clean jacocoTestReport" which will create the run configuration for you.
This helped. https://medium.com/#rafael_toledo/setting-up-an-unified-coverage-report-in-android-with-jacoco-robolectric-and-espresso-ffe239aaf3fa#.r2y0v7b5n
BIG SHOUT OUT FOR THE AUTHOR.
I want to do offline instrumentation to get coverage for my project because without that, for the server managed things (EJB's) it is showing coverage as 0%. Does anyone know how can we do offline instrumentation with gradle?
EDIT: I'm using Wildfly 8.2 application server
I don't use JaCoCo, but I've used Cobertura. As far as I know, the main superficial difference between them is that JaCoCo does runtime instrumentation, and Cobertura does compile-time instrumentation. If have no idea whether your issue with JaCoCo is fixable, but if you need to do offline or compile-time instrumentation, then you should use Cobertura.
Processing with Cobertura is as as easy as this:
plugins {
id 'net.saliman.cobertura' version '2.2.5'
}
apply plugin: 'java'
test {
filter {
includeTestsMatching "*Test"
}
}
test.dependsOn coberturaCheck
cobertura {
coverageCheckBranchRate = 0
coverageCheckLineRate = 0
coverageCheckPackageBranchRate = 0
coverageCheckPackageLineRate = 0
coverageCheckTotalBranchRate = 0
coverageCheckTotalLineRate = 0
}
I'm working on setting up the Jacoco Gradle plugin for my project. The plugin is executing fine and generating the coverage report but it's not excluding packages that I would excluded.
Classes I would like to include are in com/xxx/ws/hn/** and classes I would like excluded are in com/xxx/ws/enterprise/**.
Here's my Gradle script:
apply plugin: "jacoco"
jacoco {
toolVersion = "0.6.2.201302030002"
reportsDir = file("$buildDir/reports/jacoco")
}
test {
jacoco{
excludes = ["com/xx/ws/enterprise/**/*"]
includes = ["com/xxx/ws/hn/**/*"]
append = false
}
}
jacocoTestReport {
dependsOn test
description = "Generate Jacoco coverage reports after running tests."
executionData = files('build/jacoco/test.exec')
reports {
xml.enabled true
html.enabled true
}
}
Am I missing anything here? I've tried various patterns of exclusions including a '.' delimiter for packages instead of a '/' but nothing seems to work. Any help would be greatly appreciated.
I have not verified this but when I read the JaCoCo documentation, it states that wildcards can be used but all examples only have ONE *, not two as your example shows.
http://www.eclemma.org/jacoco/trunk/doc/agent.html
To solidify (and verify) Joachim's answer, I came across this SO post and found that specifying canonical class names, classpath style (with slashes, not periods), with single wildcard characters actually worked well. For example, here is my exclude list that works in my build, as defined as a list in a separate gradle file:
def testExcl = [
'android/*',
'com/android/*',
'com/nativelibs4java/*',
'com/ochafik/*',
'com/fasterxml/*',
'com/esotericsoftware/*',
'com/google/*',
'com/lmax/*',
'com/sun/*',
'jdk/*',
'mockit/*',
'org/apache/*',
'org/bridj/*',
'org/gradle/*',
'org/hamcrest/*',
'org/junit/*',
'org/slf4j/*',
'sun/*',
'worker/*',
'*Test',
'*TestIntegration',
'*AllTests',
'*Suite'
]
I tried probably 10 or 12 other ways of formatting the class names, and this is the only way that actually worked.
I don't know why something like this that is so simple/fundamental is so ungoogleable and difficult to find a definitive answer on in the context of Gradle (i.e. outside JaCoCo's official documentation, where no documentation exists about Gradle integration, but Ant and Maven integration docs are there).
Hopefully this helps if others are flailing trying to get JaCoCo to exclude classes.
UPDATE:
This changed in Gradle 7 (I went from 5.6.1 to 7.1.1, so not sure about Gradle 6) and no longer works.
For Gradle 7 you need to replace / with .; here are my updated exclusions:
def testExcl = [
'android.*',
'com.android.*',
'com.nativelibs4java.*',
'com.ochafik.*',
'com.fasterxml.*',
'com.esotericsoftware.*',
'com.google.*',
'com.lmax.*',
'com.sun.*',
'jdk.*',
'mockit.*',
'org.apache.*',
'org.bridj.*',
'org.gcpud.common.*',
'org.gcpud.testutil.*',
'org.gradle.*',
'org.hamcrest.*',
'org.junit.*',
'org.slf4j.*',
'sun.*',
'worker.*',
'*Test',
'*Test$*',
'*TestIntegration',
'*AllTests',
'*Suite'
]
Also see the following SO post for other means of excluding classes from reporting (exclude from reporting, not coverage itself):
Filter JaCoCo coverage reports with Gradle