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.
Related
I have a compiled jar with JUnit tests that I want to run from a docker container.
I want to do it with a Gradle task.
First, I will compile the jar and copy it with all its dependencies to a Gradle-based image.
(Or I can create a fat jar which will contain all the third party compiled to a .class).
Then I want to run the task - this task will only run tests according to a test name, JUnit tag, etc.
Is it possible to run a Gradle task on a compiled jar without having its sources?
What should I include in this image beside the gradle.build file for it to work?
Thank you
Gradle fetch transitive dependencies and run its tests in test process by default, so you can use this feature in your case.
Note that abstract classes are not executed. In addition, be aware that Gradle scans up the inheritance tree into jar files on the test classpath. So if those JARs contain test classes, they will also be run.
Gradle tests detection document.
Here is how to do it in your case :
Create an empty Gradle project and apply the java plugin.
import the test dependencies tools with the needed scopes in the dependencies section.
import myApp.jar as a local dependency.
Configure the test task (add needed properties and args).
Run Gradle test with the specific properties.
build.gradle example :
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
// just examples change with needed unit tests dependencies
testImplementation('org.junit.jupiter:junit-jupiter-api:5.4.2')
testRuntime('org.junit.jupiter:junit-jupiter-engine:5.4.2')
// the target jar file
compile file("/myApp.jar")
}
project.ext.testName = project.hasProperty("testName") ?
project.property("testName") : "*"
test {
useJUnitPlatform()
filter {
//include specific method in any of the tests
includeTestsMatching "$testName"
}
}
Now the Gradle test command will run the target tests in myApp.jar.
For more information about it check the Testing in Java & JVM projects official Gradle documents
I have to use Jacoco offline instrumentation in my project because there is PowerMock that is used as well.
The issue description: suppose you have gradle project with two modules: A, B. Module A has tests that cover a code from the module B. On code coverage data collection I figured out that coverage data(should be provided by the module A) for the module B is completely missed.
I've created a test project that demonstrates the issue: https://github.com/SurpSG/jacoco-offline-instrumentation
Jacoco offline instrumentation setup for gradle project is based on the answer https://stackoverflow.com/a/42238982/2689114
On the other hand, when I'm using jacoco gradle plugin I can observe that coverage data provided by module A for module B successfully collected to a summary report. I've created one more test project to demonstrate this: https://github.com/SurpSG/jacoco-gradle-plugin-merge-coverage
Am I have a wrong setup for the gradle multimodule project + jacoco offline instrumentation?
After some investigation, I figured out that modules dependencies in Gradle are resolved via .jar files:
<dependent-module>.classpath contains <dependency-module>.jar
So, in my case, I need to build some special jar that contains instrumented classes.
Instrumenting classes
task preprocessClassesForJacoco(dependsOn: ['classes']) {
ext.outputDir = buildDir.path + '/classes-instrumented'
doLast {
ant.taskdef(name: 'instrument',
classname: 'org.jacoco.ant.InstrumentTask',
classpath: configurations.jacoco.asPath)
ant.instrument(destdir: outputDir) {
fileset(dir: sourceSets.main.java.outputDir, includes: '**/*.class', erroronmissingdir: false)
}
}
}
The next step will be building instrumented jar:
task jacocoInstrumentedJar(type: Jar, dependsOn: [preprocessClassesForJacoco]) {
baseName "${project.name}-instrumented"
from preprocessClassesForJacoco.outputDir // path to instrumented classes
}
And finally, we need to replace the usual .jar with instrumented one
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(preprocessClassesForJacoco)) {
tasks.withType(Test) {
doFirst {
...
// getting a module dependencies
def modulesDependencies = moduleDependencies(project)
// removing regular jars
classpath -= files(modulesDependencies.jar.outputs.files)
// adding instrumented jars
classpath += files(modulesDependencies.jacocoInstrumentedJar.outputs.files)
}
}
}
}
I've updated the example project https://github.com/SurpSG/jacoco-offline-instrumentation with steps described above. Feel free to check out the project to try.
I've added a new build type called "debug_test" which has some BuildConfig differences made for testing. While I can run all the local unit tests when I switch to this build type I fail to run instrumented tests, actually I even fail to build instrumented tests when set to "debug_test" (various symbols are not there).
It looks like for my new build type the :app:generateDebugAndroidTestSources etc are not executed.
Debug runs:
Executing tasks: [:app:generateDebugSources, :app:generateDebugAndroidTestSources, :app:mockableAndroidJar]
Whereas debug_test runs:
Executing tasks: [:app:generateDebug_testSources, :app:mockableAndroidJar]
I struggle a little bit to grasp what I have to do mainly because I do not understand which operations are implicitly done for debug which I need to do for debug_test as well. Do I need to explicitly define task dependency to generateDebugAndroidTestSources in my app level build.gradle file?
Hints appreciated.
Well this post here Android instrumented unit testing Cannot resolve symbol 'AndroidJUnit4' has an answer.
It looks like you can only have one instrumented test configuration.
This document https://developer.android.com/studio/build/gradle-tips.html#change-the-test-build-type briefly mentions that but the implication is not clear.
Your android configuration in the app's gradle file looks like that:
android {
...
defaultConfig {
...
}
testBuildType "debug" // This is not in the gradle file but this is implicitly set
buildTypes {
release {
...
}
debug {
}
debug_test {
debuggable true
signingConfig signingConfigs.debug
}
}
}
So to change on which configuration the instrumented tests are compiled the line testBuildType <my_config> must be added to the android configuration set.
It would be very nice if there would be a way to see all those implicit options.
I'm using Intillij with gradle 3.5 and I want to call specific class in project. in me build.gradle I have
ext.testFile = System.getProperty('Test_Plan') ?: 'testng.xml'
test {
ignoreFailures = true
testLogging {
events 'started', 'passed'
}
useTestNG {
suites "src/main/resources/${testFile}"
}
}
that use to call suite in my project, but I'll want to ignore the 'test' and just call from terminal
gradle test --tests TC1001 or gradle test -Dtest.single=TC1001
and this 2 options give the error
* What went wrong:
Execution failed for task ':test'.
No tests found for given includes: [com.automation.navigateSuite.TC1001]
the directory hierarchy is
src/test/java/com.automation/navigateSuite/TC1001.java
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.