Way to get Gradle Jacoco to Output Coverage to Console? - java

In python, using Coverage.py we are able to get line information about code coverage on the command line using coverage report --show-missing. This showed what lines of each file weren't being covered.
Using gradle plugins, the best output I can get is:
- Class Coverage: 10%
- Method Coverage: 3.2%
- Branch Coverage: 100%
- Line Coverage: 1.2%
- Instruction Coverage: 1.1%
- Complexity Coverage: 3.2%
However as this does not give line information, you may as well just look at html output.
My test.gradle file:
buildscript {
repositories {
mavenCentral()
}
}
plugins {
id 'application'
id 'jacoco'
id 'com.github.ksoichiro.console.reporter' version '0.6.2'
id 'org.barfuin.gradle.jacocolog' version '1.2.4'
}
dependencies {
implementation files('lib/json.jar')
implementation files('lib/junit-platform-console-standalone-1.7.0-M1.jar')
implementation files('lib/jsonassert-1.2.3.jar')
}
test {
useJUnitPlatform()
finalizedBy jacocoTestReport // report is always generated after tests run
ignoreFailures = true
}
test.outputs.upToDateWhen {false}
jacocoTestReport {
dependsOn test // tests are required to run before generating the report
}
repositories {
mavenCentral()
}
group 'unsw.blackout'
apply plugin: 'java'
sourceSets.test.java.srcDirs = ['src']
sourceSets.test.java.excludes = ['degree/*']
sourceSets.main.java.srcDirs = ['src']
sourceSets.main.java.excludes = ['degree/*']
Is there an equivalence for gradle?

Related

Publishing is not able to resolve a dependency on a project with multiple publications that have different coordi nates

I intend to publish my modules in a nexus repository with the following steps.
first step:
Create a android-publications.gradle file and add the following contents to it
android-publications.gradle :
apply plugin: 'maven-publish'
ext.moduleVersion = "0.0.0"
def moduleGroupId = "team.techvida.framework"
def moduleRepoUrl = "http://url/repository/maven-releases/"
afterEvaluate {
publishing {
publications {
debug(MavenPublication) {
from components.debug
groupId = moduleGroupId
artifactId = "$project.name-debug"
version = moduleVersion
}
release(MavenPublication) {
from components.release
groupId = moduleGroupId
artifactId = project.name
version = moduleVersion
}
}
repositories {
maven {
name "nexus"
url moduleRepoUrl
allowInsecureProtocol = true
credentials {
username findProperty("nexusUsername")
password findProperty("nexusPassword")
}
}
}
}
}
Step two
Use it in all modules as follows:
core module =>
apply from: "$rootDir/android-library-build.gradle"
apply from: "$rootDir/buildSrc/android-publications.gradle"
ext.moduleVersion = "0.0.1"
dependencies {
}
presentation module =>
apply from: "$rootDir/android-library-build.gradle"
apply from: "$rootDir/buildSrc/android-publications.gradle"
ext.moduleVersion = "0.0.1"
dependencies {
}
Third step
Use in a module that uses other modules
di module =>
apply from: "$rootDir/android-library-build.gradle"
apply from: "$rootDir/buildSrc/android-publications.gradle"
ext.moduleVersion = "0.0.1"
dependencies {
implementation(project(Modules.core))
implementation(project(Modules.imageLoading))
implementation(project(Modules.prettyLogger))
}
Note 1 : Publishing the second step modules is done successfully.
Step 4 (which leads to a compilation error)
Publish the third step module (di)
Received error:
What went wrong:
Could not determine the dependencies of task ':di:publishReleasePublicationToNexusRepository'.
> Publishing is not able to resolve a dependency on a project with multiple publications that have different coordi
nates.
Found the following publications in project ':image_loading':
- Maven publication 'debug' with coordinates team.techvida.framework:image_loading-debug:0.0.1
- Maven publication 'release' with coordinates team.techvida.framework:image_loading:0.0.1
* 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.
Would you please tell me how to solve this problem?

Kotlin JaCoCo - IllegalClassFormatException. Please supply original non-instrumented classes

I'm trying to get test coverage report of our Android application module and executing the testVariantBuildTypeUnitTest task.
Although all tests are passed, TEST-classNameTest.xml file contains error message below. This error is only given for methods contain calls Java from Kotlin. Is there any solution for this issue ?
**Caused by: java.lang.IllegalStateException: Cannot process instrumented class... Please supply original non-instrumented classes.
at org.jacoco.agent.rt.internal_f3994fa.core.internal.instr.InstrSupport.assertNotInstrumented(InstrSupport.java:238)
at org.jacoco.agent.rt.internal_f3994fa.core.internal.instr.ClassInstrumenter.visitField(ClassInstrumenter.java:56)
at org.jacoco.agent.rt.internal_f3994fa.asm.ClassVisitor.visitField(ClassVisitor.java:339)
at org.jacoco.agent.rt.internal_f3994fa.asm.ClassReader.readField(ClassReader.java:1111)
at org.jacoco.agent.rt.internal_f3994fa.asm.ClassReader.accept(ClassReader.java:713)
at org.jacoco.agent.rt.internal_f3994fa.asm.ClassReader.accept(ClassReader.java:401)
at org.jacoco.agent.rt.internal_f3994fa.core.instr.Instrumenter.instrument(Instrumenter.java:90)
at org.jacoco.agent.rt.internal_f3994fa.core.instr.Instrumenter.instrument(Instrumenter.java:108)
We have multimodule android project, because of this we're using this custom Jacoco task to get coverage report:
project.afterEvaluate {
(android.hasProperty('applicationVariants')
? android.'applicationVariants'
: android.'libraryVariants')
.all { variant ->
def variantName = variant.name
def unitTestTask = "test${variantName.capitalize()}UnitTest"
def jacocoReportName = unitTestTask + project.name
tasks.create(name: jacocoReportName, type: JacocoReport, dependsOn: [
"$unitTestTask"
]) {
group = "Reporting"
description = "Generate Jacoco coverage reports for the ${variantName.capitalize()} build"
reports {
html.enabled = true
xml.enabled = true
}
def fileFilter = [
// data binding
'android/databinding/**/*.class',
'**/android/databinding/*Binding.class',
'**/android/databinding/*',
'**/androidx/databinding/*',
'**/databinding',
'**/BR.*',
// android
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*'
]
def javaClasses = fileTree(dir: variant.javaCompileProvider.get().destinationDir,
excludes: fileFilter)
def kotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/${variantName}",
excludes: fileFilter)
classDirectories.setFrom(files([
javaClasses,
kotlinClasses
]))
def variantSourceSets = variant.sourceSets.java.srcDirs.collect { it.path }.flatten()
sourceDirectories.setFrom(project.files(variantSourceSets))
if (isAndroidLibrary(project)) {
executionData(files([
"${projectDir}/jacoco.exec"
]))
}else{
executionData(files([
"$project.buildDir/jacoco/${project.name}.exec"
]))
}
}
}
}
Regards,
Solution
The problem most likely lies in your module level build.gradle file. You need to remove testCoverageEnabled or set it to false.
android {
...
buildTypes {
release {
minifyEnabled true
}
debug {
// testCoverageEnabled true
minifyEnabled false
}
}
Explanation and References
Firstly I've been struggling with unit test coverage on android with JaCoCo for years and repeatedly encountered the issues multiple times as the AGP (Android Gradle Plugin) team enhanced the AGP (e.g. Similar issue) therefore this solution is subject to change in future releases of the AGP.
Come the release of AGP 4.1 the AGP team changed the way the plugin deals with unit tests. I raised an enter link description here issue with the AGP team and they explained that the plugin (AGP 4.1+) does it's own form of instrumentation to get the coverage which is undoubtedly incompatible with JaCoCo. It was in this issue where the solution was highlighted to me.
Note 1: This issue is not documented in the DSL documentation!
Note 2: It should also be noted that as of when I wrote this AGP 7 is in development where the same issue occurs.
Considerations
This solution will cause a problem generating coverage for instrumented tests as the AGP generates coverage for instrumented tests (in the form of a .ec file) meaning to get instrumented test coverage you must have testCoverageEnabled true.
As a workaround you could:
Put your unit tests in the release build variant
Put your instrumented tests in the debug build variant.
It's still possible to combine the coverage into one report: for example:
task jacocoCombinedUnitTestAndroidTestReport(type: JacocoReport) {
group = "Reporting"
reports {
xml.enabled = true
html.enabled = true
}
def mainSrc = "$project.projectDir/src/main/java"
def releaseKotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/release", excludes:["com/example/ui**"])
def debugKotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug/com/example/ui/")
def releaseJavaClasses = fileTree(dir: "${buildDir}/intermediates/javac/release", excludes: ["com/example/ui**"])
def debugJavaClasses = fileTree(dir: "${buildDir}/intermediates/javac/debug/com/example/ui/" )
def mainClasses = releaseKotlinClasses + debugKotlinClasses
def javaClasses = releaseJavaClasses + debugJavaClasses
sourceDirectories.from = files([mainSrc])
classDirectories.from = files([mainClasses, javaClasses])
executionData.from = fileTree(dir: buildDir, include: ["jacoco/testReleaseUnitTest.exec",
"outputs/code_coverage/debugAndroidTest/connected/**.ec"])
}
This assumes you have any UI code in a ui directory.
You include all release classes excluding the ui directory
You only include your ui debug classes.
Please note this is only valid as of when this answer was written and hopefully Google will fix the issue in the future.

Cannot add task ':jacocoTestReport' as a task with that name already exists

I am trying to add the following task so that I can get some coverage data in my java + kotlin project (for what it is worth, this is a gradle project)... but I get the following error :
"Cannot add task ':jacocoTestReport' as a task with that name already exists"
Here is the actual task I am trying to add :
task jacocoTestReport(type: JacocoReport, dependsOn: "testDebugUnitTest") {
group = "Reporting"
description = "Generate Jacoco coverage reports for Debug build"
reports {
xml.enabled = true
html.enabled = true
}
// what to exclude from coverage report
// UI, "noise", generated classes, platform classes, etc.
def excludes = [
'**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
'android/**/*.*',
'**/*Fragment.*',
'**/*Activity.*'
]
// generated classes
classDirectories = fileTree(
dir: "$buildDir/intermediates/classes/debug",
excludes: excludes
) + fileTree(
dir: "$buildDir/tmp/kotlin-classes/debug",
excludes: excludes
)
// sources
sourceDirectories = files([
android.sourceSets.main.java.srcDirs,
"src/main/kotlin"
])
executionData = files("$buildDir/jacoco/testDebugUnitTest.exec")
}
Now, the issue I am confused about here, is that I can't find another class of this name anywhere... so perhaps there is something funky going on? I have tried googling this, but haven't really been able to find anything which truly helps me solve the problem.
All help greatly appreciated. I realize this is not a java or kotlin specific problem - but since it is a joint java + kotlin project, I thought I would tag both in this question, in case there is some nuanced issue that somebody else has seen.
Assuming you're already applying the Jacoco Gradle plugin, then yes, it already defines a task called jacocoTestReport, hence the error.
All you need to do is define your specific settings as per the documentation https://docs.gradle.org/current/userguide/jacoco_plugin.html#sec:jacoco_report_configuration
an example is below:
jacocoTestReport {
dependsOn "testDebugUnitTest"
reports {
xml.enabled = true
html.enabled = true
}
}
Most of the other configuration items you've listed belong in the 'jacoco' configuration block.
https://docs.gradle.org/current/userguide/jacoco_plugin.html#sec:jacoco_specific_task_configuration

ANTLR4 does not find grammar on import

I am trying to split my ANTLR4 grammar in multiple files so i can test them more easily, i am using gradle as a build tool in a java project.
Both grammar compile correctly by separate but when i add the import to my main grammar i get the next compilation error
error(110): kanekotic/specflow/rider/SpecflowFeature.g4:3:7: can't find or load grammar SpecflowScenario
the inherited grammar looks like:
grammar SpecflowScenario;
#header {
package kanekotic.specflow.rider;
}
scenario
: 'Scenario: ';
and the main grammar looks like:
grammar SpecflowFeature;
import SpecflowScenario;
#header {
package kanekotic.specflow.rider;
}
file returns [List<String> values]
#init { $values = new ArrayList<String>(); }
: 'Feature: ' EOF;
What am i doing wrong? is this not allowed?
edit:
the gradle.build looks like:
plugins {
id "org.jetbrains.intellij" version "0.1.10"
}
apply plugin: 'org.jetbrains.intellij'
apply plugin: 'java'
apply plugin: 'antlr'
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
intellij {
version '143.2370.31'
pluginName 'Specflow Rider'
}
group 'kanekotic.specflow.rider'
version '0.1'
repositories {
mavenCentral()
jcenter()
}
dependencies {
antlr "org.antlr:antlr4:4.5"
testCompile 'junit:junit:4.12'
testCompile "org.mockito:mockito-core:2.+"
}
all the code as it is open sourced is in this next link: https://github.com/kanekotic/Specflow.Rider/tree/antlr4_multiple_grammar
The Antlr plugin uses src/main/antlr as lib directory by default. As the grammar file to include is in kanekotic/specflow/rider, use the following code in your gradle file to include this location:
generateGrammarSource {
arguments << "-lib" << "src/main/antlr/kanekotic/specflow/rider"
}
See also this gradle thread.

Get dependencies from subproject within root project

Can't get the subproject dependencies in root build file. They isn't initialized for some reasons.
Is there a possibility to get list of dependencies from project1 for example inside root ?
Pls see copyToLib task. It should return values from dependencies section of project1, but actually it's not.
Gradle version is 2.0
Root
|
|-project1
| |-build.gradle
|-project2
| |-build.gradle
|-core1
| |-build.gradle
|-core2
| |-build.gradle
|-build.gradle
|-settings.gradle
settings.gradle
include 'project1','project2','core1','core2'
rootProject.name="Root"
project1:build.gradle
version = '0.1'
dependencies {
compile project(':core1'),
project(':core2'),
'org.springframework:spring-web:4.0.6.RELEASE'
}
root:build.gradle
subprojects{
apply plugin: 'java'
apply plugin: 'eclipse'
apply from: "${rootProject.projectDir}/eclipse.gradle"
sourceCompatibility = 1.7
repositories {
mavenCentral()
}
task copyToLib(type: Copy) {
def deps = project.configurations.compile.getAllDependencies().withType(ProjectDependency)
for ( dep in deps ) {
println dep.getDependencyProject().projectDir
}
}
build.dependsOn(copyToLib)
}
When project variable is used in subprojects it refers to the current project - in this particular case - root.
You need to remove adding the task from subprojects closure and add the following piece of code:
subprojects.each { p ->
configure(p) {
task copyToLib << {
def deps = p.configurations.compile.allDependencies.withType(ProjectDependency)
for ( dep in deps ) {
println dep.getDependencyProject().projectDir
}
}
p.build.dependsOn(copyToLib)
}
}
Have simplified the task (it's not of type Copy) - You need to differentiate task action from configuration.

Categories

Resources