I have been working on an android project in kotlin where I have a few packages: app, package1, package2, package3 each package has its own build.gradle like build.gradle for app, package1, package2, package3 in the respective package.
There is also a top-level build.gradle. Now each package has a src and a tests folder. Now I have created a jacoco.gradle file in the package.root. and applied apply from: "$project.rootDir/jacoco.gradle" in each package's build.gradle.
Here is my jacoco.gradle file for reference.
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.8.6"
}
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
}
project.afterEvaluate {
(android.hasProperty('applicationVariants')
? android.'applicationVariants'
: android.'libraryVariants').all { variant ->
def variantName = variant.name
def unitTestTask = "test${variantName.capitalize()}UnitTest"
def uiTestCoverageTask = "create${variantName.capitalize()}CoverageReport"
tasks.create(name: "${unitTestTask}Coverage", type: JacocoReport, dependsOn: [
"$unitTestTask",
"$uiTestCoverageTask"
]) {
group = "Reporting"
description = "Generate Jacoco coverage reports for the ${variantName.capitalize()} build"
reports {
html.enabled = true
xml.enabled = false
csv.enabled = false
}
def fileFilter = [
// data binding
'android/databinding/**/*.class',
'**/android/databinding/*Binding.class',
'**/android/databinding/*',
'**/androidx/databinding/*',
'**/BR.*',
// android
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
'android/**/*.*',
// kotlin
'**/*MapperImpl*.*',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/*Component*.*',
'**/*BR*.*',
'**/Manifest*.*',
'**/*$Lambda$*.*',
'**/*Companion*.*',
'**/*Module*.*',
'**/*Dagger*.*',
'**/*MembersInjector*.*',
'**/*_MembersInjector.class',
'**/*_Factory*.*',
'**/*_Provide*Factory*.*',
'**/*Extensions*.*',
// sealed and data classes
'**/*$Result.*',
'**/*$Result$*.*'
]
classDirectories.setFrom(files([
fileTree(dir: "${buildDir}/tmp/kotlin-classes/${variantName}", excludes: fileFilter)
]))
def variantSourceSets = variant.sourceSets.java.srcDirs.collect { it.path }.flatten()
sourceDirectories.setFrom(project.files(variantSourceSets))
def uiTestsData = fileTree(dir: "${buildDir}/outputs/code_coverage/${variantName}AndroidTest/connected/", includes: ["**/*.ec"])
executionData(files([
"$project.buildDir/jacoco/${unitTestTask}.exec",
uiTestsData
]))
}
}
}
Now the problem is when I run the testDebugUnitTestCoverage task even though all tests present in a package pass the results show 0% code coverage and all lines are missed. Can someone help me find a solution?
Update
The coverage is reported with app package and package2(without any change in any files) but jacoco still reports 0 coverage for package1 and package3
Edit
added gradle file for 1 of the failing package
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply from: "$project.rootDir/jacoco.gradle"
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
minSdkVersion 19
targetSdkVersion 29
versionCode 1
versionName "1.0"
multiDexEnabled true
javaCompileOptions {
annotationProcessorOptions {
includeCompileClasspath true
}
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
}
testOptions {
unitTests {
includeAndroidResources = true
all {
forkEvery = 1
maxParallelForks = Runtime.getRuntime().availableProcessors()
testLogging {
events "passed", "skipped", "failed"
showExceptions = true
exceptionFormat = "full"
showCauses = true
showStackTraces = true
showStandardStreams = false
}
}
}
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
testCoverageEnabled true
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation(
'androidx.appcompat:appcompat:1.0.2',
'androidx.exifinterface:exifinterface:1.0.0-rc01',
'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha03',
'androidx.work:work-runtime-ktx:2.4.0',
'com.google.dagger:dagger:2.24',
'com.google.firebase:firebase-analytics-ktx:17.5.0',
'com.google.firebase:firebase-crashlytics:17.0.0',
"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
)
testImplementation(
'android.arch.core:core-testing:1.1.1',
'androidx.test.espresso:espresso-core:3.2.0',
'androidx.test.ext:junit:1.1.1',
'androidx.work:work-testing:2.4.0',
'com.google.dagger:dagger:2.24',
'com.google.truth:truth:0.43',
'junit:junit:4.12',
"org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version",
'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.2',
'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.2.2',
'org.mockito:mockito-core:2.19.0',
'org.robolectric:robolectric:4.3',
project(":package2"),
)
kapt(
'com.google.dagger:dagger-compiler:2.24',
)
kaptTest(
'com.google.dagger:dagger-compiler:2.24',
)
api project(':package1')
implementation project(':package4')
implementation project(':package3')
}
repositories {
mavenCentral()
}
configurations {
all*.exclude module: 'protobuf-java'
}
update
when I run coverage from run configurations in android studio I get the correct data but when I run it from gradle tasks it shows 0 coverage.
Related
I'm trying to barteksc/AndroidPdfViewer in my android project but it fail to load the lib and I can't figure out why... Any Idea?
Here's my config :
build.gradle (:app)
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'jacoco'
id 'com.google.gms.google-services'
id 'dagger.hilt.android.plugin'
}
apply plugin: 'kotlin-kapt'
android {
compileSdk 31
defaultConfig {
applicationId "com.github.multimatum_team.multimatum"
minSdk 26
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "com.github.multimatum_team.multimatum.MultimatumTestRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
testCoverageEnabled true
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
testOptions {
unitTests {
includeAndroidResources = true
returnDefaultValues = true
}
}
testCoverage {
jacocoVersion = "0.8.7"
}
}
dependencies {
implementation fileTree(dir: "libs", include:["*.jar"])
implementation 'com.github.barteksc:android-pdf-viewer:3.2.0-beta.1'
implementation 'com.google.code.gson:gson:2.8.9'
implementation "androidx.preference:preference-ktx:1.2.0"
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
....
testImplementation 'org.mockito:mockito-core:4.4.0'
testImplementation 'com.linkedin.dexmaker:dexmaker-mockito:2.28.1'
}
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
jacoco.includes = ["com.application.*"]
}
task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {
reports {
xml.enabled true
html.enabled true
}
def fileFilter = [
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
'android/**/*.*',
// Exclude Hilt generated classes
'**/*Hilt*.*',
'hilt_aggregated_deps/**',
'**/*_Factory.class',
'**/*_MembersInjector.class'
]
def debugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter)
def mainSrc = "$project.projectDir/src/main/java"
sourceDirectories.setFrom(files([mainSrc]))
classDirectories.setFrom(files([debugTree]))
executionData.setFrom(fileTree(dir: project.buildDir, includes: [
'outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec',
'outputs/code_coverage/debugAndroidTest/connected/*/coverage.ec'
]))
}
connectedCheck {
finalizedBy jacocoTestReport
}
// Allow references to generated code
kapt {
correctErrorTypes = true
}
build.gradle (project
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories{
google()
}
dependencies {
classpath 'com.google.gms:google-services:4.3.10'
classpath("com.google.dagger:hilt-android-gradle-plugin:2.38.1")
}
}
plugins {
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
}
task clean(type: Delete) {
delete rootProject.buildDir
}
error : "Could not resolve com.github.barteksc:android-pdf-viewer:3.2.0-beta.1."
I haven't found why I cannot load a library from github. Do I have to use something like jitpack?
I cannot use maven since the lib doesn't support it.
You can't just link to code in github like that. It needs to be packaged into a library and downloaded in compiled form. You have to use maven or similar repository. Gradle doesn't even know how to download source code from git for a dependency, it only expects packaged code.
I wouldn't use this library in any case. It hasn't been updated in 3 years, and the first line of its readme is that its looking for a new maintainer. And since it has no updates, it didn't find one. I would be vary wary of some random library on github, and doubly wary of one that's not maintained.
Need help on enforcing code coverage metrics. I have based my solution on this blog post.
I have already referred following posts in an attempt to solve this problem.
this series of posts
this one on Jacoco with java project (not android)
this official documentation
this one was supposed to be a straight answer
many more SO questions and blogs
(Really embarrassing - still it looks like I'm missing something :( )
I am able to get the code coverage but not able to enforce minimum threshold.
Here is how my Jacoco.gradle looks like -
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.8.2"
}
project.afterEvaluate {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type ->
type.name
}
def productFlavors = android.productFlavors.collect { flavor ->
flavor.name
}
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
task "${testTaskName}Coverage" (type:JacocoReport, dependsOn: "$testTaskName") {
reports {
xml.enabled = true
html.enabled = true
}
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
classDirectories = fileTree(
dir: "${project.buildDir}/intermediates/javac/${buildTypeName}",
excludes: [
'**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/Manifest*.*'
]
)
def coverageSourceDirs = [
"src/main/java",
"src/$productFlavorName/java",
"src/$buildTypeName/java"
]
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
}
}
}
}
I have included the above script in app module's build.gradle.
apply plugin: 'com.android.application'
apply from: '../jacoco.gradle'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.jacocodemo"
minSdkVersion 27
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
testCoverageEnabled = true
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
I have tried many different approaches so far. Looks like the Jacoco documentation is biased towards plain java projects as the code snippets almost always need changes when used in android, but even then no luck.
Here's my attempt to solve this -
(just give the Jacoco.gradle here as the main code is in it)
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.8.2"
}
// ****** THIS IS MY ATTEMPT AT IT [START] ******
task jacocoTestCoverageVerification(type: JacocoCoverageVerification) {
violationRules {
rule {
enabled = true
limit {
minimum = 0.9
}
}
}
}
check.dependsOn jacocoTestCoverageVerification
// ****** THIS IS MY ATTEMPT AT IT [END] ******
project.afterEvaluate {
// Grab all build types and product flavors
def buildTypes = android.buildTypes.collect { type ->
type.name
}
def productFlavors = android.productFlavors.collect { flavor ->
flavor.name
}
// When no product flavors defined, use empty
if (!productFlavors) productFlavors.add('')
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
def sourceName, sourcePath
if (!productFlavorName) {
sourceName = sourcePath = "${buildTypeName}"
} else {
sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
sourcePath = "${productFlavorName}/${buildTypeName}"
}
def testTaskName = "test${sourceName.capitalize()}UnitTest"
// Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
task "${testTaskName}Coverage" (type:JacocoReport, dependsOn: "$testTaskName") {
reports {
xml.enabled = true
html.enabled = true
}
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
classDirectories = fileTree(
dir: "${project.buildDir}/intermediates/javac/${buildTypeName}",
excludes: [
'**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/Manifest*.*'
]
)
def coverageSourceDirs = [
"src/main/java",
"src/$productFlavorName/java",
"src/$buildTypeName/java"
]
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
}
}
}
}
and then I tried invoking it as follows:
gradle clean build testDebugUnitTestCoverage jacocoTestCoverageVerification.
Any help on this is much appreciated.
My root build.gradle file
buildscript {
repositories {
google()
mavenCentral()
jcenter()
maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath "org.jacoco:org.jacoco.core:0.8.0"
}
}
apply plugin: 'android-sdk-manager'
allprojects {
apply plugin: 'jacoco'
apply plugin: 'com.github.ben-manes.versions'
repositories {
google()
mavenCentral()
jcenter()
flatDir {
dirs 'libs'
}
}
tasks.withType(JavaCompile) {
sourceCompatibility = JavaVersion.VERSION_1_10
targetCompatibility = JavaVersion.VERSION_1_10
// report all Java errors even if the IDE does not
configure(options) {
compilerArgs << '-Xlint:all' << '-Xlint:-options'
deprecation = true
encoding = 'UTF-8'
}
}
// print errors from test in the terminal
tasks.withType(Test) {
testLogging {
exceptionFormat 'full'
}
}
project.plugins.whenPluginAdded { plugin ->
if ("com.android.build.gradle.AppPlugin".equals(plugin.class.name)) {
println "Disable pre dexing for module ${project.name}"
project.android.dexOptions.preDexLibraries = false
} else if ("com.android.build.gradle.LibraryPlugin".equals(plugin.class.name)) {
println "Disable pre dexing for module ${project.name}"
project.android.dexOptions.preDexLibraries = false
}
}
}
app/build.gradle file
apply plugin: 'com.android.application'
apply from: '../jacoco.gradle'
android {
compileSdkVersion COMPILE_SDK_VERSION as int
buildToolsVersion BUILD_TOOLS_VERSION
defaultConfig {
applicationId "..."
minSdkVersion MIN_SDK_VERSION as int
targetSdkVersion TARGET_SDK_VERSION as int
project.ext.set("archivesBaseName", "..." + versionName)
multiDexEnabled true
renderscriptTargetApi RENDERSCRIPT_TARGET_API as int
renderscriptSupportModeEnabled true
}
signingConfigs {
debugKey {
...
}
releaseKey {
...
}
}
buildTypes {
debug {
versionNameSuffix ''
debuggable true
minifyEnabled false
zipAlignEnabled true
signingConfig signingConfigs.debugKey
testCoverageEnabled true
}
staging {
versionNameSuffix ''
debuggable false
minifyEnabled true
zipAlignEnabled true
signingConfig signingConfigs.stagKey
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
matchingFallbacks = ['release']
}
release {
versionNameSuffix ''
debuggable false
minifyEnabled true
zipAlignEnabled true
signingConfig signingConfigs.releaseKey
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'LICENSE.txt'
}
testOptions {
animationsDisabled true
unitTests {
returnDefaultValues = true
includeAndroidResources = true
}
}
lintOptions {
lintConfig file('lint.xml')
abortOnError false
}
sourceSets {
main {
java.srcDirs = ['src/main/java']
}
}
dexOptions {
javaMaxHeapSize "3g"
jumboMode = true
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// Espresso
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
// Junit
testImplementation "junit:junit:${JUNIT_VERSION}"
//Mockito
testImplementation "org.mockito:mockito-core:2.22.0"
...
}
and jacoco.gradle file
apply plugin: 'jacoco'
def buildDir = "$project.buildDir"
def taskName = "debug"
def testTaskName = "testDebugUnitTest"
jacoco {
toolVersion "0.7.7.201606060606"
}
task "${testTaskName}Coverage"(type: JacocoReport, dependsOn: ["${testTaskName}", "createDebugCoverageReport"]) {
group = "Reporting"
description = "Generate Jacoco coverage reports on the ${testTaskName} build."
reports {
xml.enabled = true
html.enabled = true
html.destination file("$buildDir/jacoco")
csv.enabled false
}
def coverageSourceDirs = ["src/main/java"]
def fileFilter = [
'**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/Manifest*.*',
'android/**',
'com/google/**',
'com/intellij/**',
'junit/**',
'net/**',
'okhttp/**',
'org/**',
'rx/**',
'**/*_MembersInjector.class',
'**/Dagger*Component.class', // covers component implementations
'**/Dagger*Component$Builder.class', // covers component builders
'**/*Module_*Factory.class'
]
def javaClasses = fileTree(
dir: "$buildDir/intermediates/app_classes/${taskName}",
excludes: fileFilter
)
classDirectories = files([javaClasses])
sourceDirectories = files([coverageSourceDirs])
additionalSourceDirs = files([coverageSourceDirs])
executionData = fileTree(dir: "$buildDir", includes: [
"jacoco/testDebugUnitTest.exec"
])
}
and I am running following command on mac
./gradlew clean testDebugUnitTestCoverage
When I run this command, it shows message
Task ':app:testDebugUnitTestCoverage' is not up-to-date because:
Output property 'reports.enabledDirectoryReportDestinations.html' file .../app/build/jacoco/index.html has been removed.
Output property 'reports.enabledDirectoryReportDestinations.html' file .../app/build/jacoco/jacoco-sessions.html has been removed.
Output property 'reports.enabledDirectoryReportDestinations.html' file .../app/build/jacoco/jacoco-resources has been removed.
[ant:jacocoReport] Loading execution data file .../app/build/jacoco/testDebugUnitTest.exec
[ant:jacocoReport] Writing bundle 'app' with 3040 classes
and no coverage gets calculated in folder
reports/coverage/debug
however folder
tests/testDebugUnitTest
shows passed unit tests data with success.
I found solution here.
Just change path of classes directory
def javaClasses = fileTree(
dir: "$buildDir/intermediates/javac/debug",
excludes: fileFilter
)
I wrote an article a while ago about jacoco.
https://github.com/uriel-frankel/android-code-coverage/
The jacoco version should change as well:
apply plugin: 'jacoco'
jacoco {
toolVersion = '0.7.5.201505241946'
}
I want to use Checker Framework to do some static analysis of my app- checking for Nullability failures, UI constraint failures, etc at runtime. I followed the instructions at https://checkerframework.org/manual/#android-gradle to try and make it run, but I'm getting an error that checkTypes is not a task. I think I followed the instructions correctly, and I fixed the capitalization mismatch they had. ANy ideas how to fix it? My build.gradle is below:
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.+'
}
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
repositories {
maven { url 'https://maven.fabric.io/public' }
google()
}
apply plugin: 'jacoco'
apply plugin: 'com.getkeepsafe.dexcount'
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xmaxerrs" << "500"
}
}
android {
compileSdkVersion 25
buildToolsVersion '26.0.2'
defaultConfig {
applicationId "com.handshake.hsdm"
minSdkVersion 19
targetSdkVersion 25
versionCode 35
versionName "0.0.35"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
testCoverageEnabled = false
}
debug {
testCoverageEnabled = false
}
checkTypes {
javaCompileOptions.annotationProcessorOptions.
classNames.add("org.checkerframework.checker.guieffect.GuiEffectChecker")
// You can pass options like so:
// javaCompileOptions.annotationProcessorOptions.arguments.put("warns", "")
}
}
dexOptions {
preDexLibraries = false
}
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
packagingOptions {
//These files constantly step on each other from multiple libraries, don't include them
exclude 'META-INF/ASL2.0'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
exclude 'META-INF/*'
exclude 'plugin.xml'
exclude 'plugin.properties'
exclude 'about_files/LICENSE-2.0.txt'
}
testOptions {
unitTests.all {
jacoco {
includeNoLocationClasses = true
}
}
}
jacoco {
version = '0.7.3.201502191951'
}
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:2.0.1'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
configurations {
checkerFrameworkAnnotatedJDK {
description = 'a copy of JDK classes with Checker Framework type qualifers inserted'
}
}
task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {
reports {
xml.enabled = true
html.enabled = true
}
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*',
'com/handshake/hsdm/demo/**','com/handshake/hsdm/localstorage/schema1/*Dao*',
'com/handshake/hsdm/localstorage/schema1/*Factory*', 'com/handshake/hsdm/dagger2',
'**/*Module*', '**/*_Factory*', '**/*_MembersInjector*'
]
def debugTree = fileTree(dir: "${buildDir}/intermediates/classes/debug", excludes: fileFilter)
def mainSrc = "${project.projectDir}/src/main/java"
sourceDirectories = files([mainSrc])
classDirectories = files([debugTree])
executionData = fileTree(dir: "$buildDir", includes: [
"jacoco/testDebugUnitTest.exec",
"outputs/code-coverage/connected/*coverage.ec"
])
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it, exclude: ['com/handshake/hsdm/demo/**'])
})
}
}
dependencies {
//Clipping dependencies
ext.checkerFrameworkVersion = '2.2.1'
implementation "org.checkerframework:checker-qual:${checkerFrameworkVersion}"
annotationProcessor "org.checkerframework:checker:${checkerFrameworkVersion}"
checkerFrameworkAnnotatedJDK "org.checkerframework:jdk8:${checkerFrameworkVersion}"
}
apply plugin: 'com.google.gms.google-services'
gradle.projectsEvaluated {
tasks.withType(JavaCompile).all { compile ->
if (compile.name.contains("checkTypes")) {
compile.options.compilerArgs += [
"-Xbootclasspath/p:${configurations.checkerFrameworkAnnotatedJDK.asPath}"
]
}
}
}
Edit: For future readers- the line javaCompileOptions.annotationProcessorOptions.classNames +=["org.checkerframework.checker.nullness.NullnessChecker"] seems to be the problem. removing it runs dagger and other annotation processors, but obviously won't run the checker.
So apparently if you specify 1 annotation processor via classnames, it overwrites any others. So I had to specify dagger and autofactory as well. Then I can either run it from Android Studio as a build, or from command line as:
gradlew assembleCheckTypes
Below is the build.gradle file
apply plugin: 'android'
apply plugin: 'jacoco'
android {
compileSdkVersion 'Google Inc.:Google APIs:19'
buildToolsVersion "19.1.0"
jacoco {
version = '0.6.2.201302030002'
}
dexOptions {
preDexLibraries = false
}
android.enforceUniquePackageName=false
sourceSets {
androidTest {
java.srcDirs = ['\\src\\androidTest\\java', '\\src\\integTest\\
}
main {
manifest.srcFile('src/main/AndroidManifest.xml')
java.srcDir file('src/main/java')
res.srcDirs = ['src/main/res']
}
}
defaultConfig {
minSdkVersion 9
targetSdkVersion 17
versionCode 35
versionName "3.4.5"
testInstrumentationRunner "android.test.InstrumentationTestRunner"
}
buildTypes {
debug {
testCoverageEnabled = true
}
}
}
Any one have idea what I'm missing.
I'm using this gradle task for JaCoCo reports.
classDirectories -> excludes - look at this line in the task.
def coverageSourceDirs = [
'src/test/java'
]
task jacocoTestReport(type:JacocoReport, dependsOn: "testDebug") {
group = "Reporting"
description = "Generate Jacoco coverage reports"
classDirectories = fileTree(
dir: "$buildDir/intermediates/classes/debug",
// Specify here files and packages which should be excluded from reports
excludes: ['**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/BuildConfig.*',
'**/Manifest*.*']
)
reports {
xml.enabled = true
html.enabled = true
}
additionalSourceDirs = files(coverageSourceDirs)
sourceDirectories = files(coverageSourceDirs)
executionData = files("$buildDir/jacoco/testDebug.exec")
// Bit hacky but fixes https://code.google.com/p/android/issues/detail?id=69174.
// We iterate through the compiled .class tree and rename $$ to $.
doFirst {
new File("$buildDir/intermediates/classes/").eachFileRecurse { file ->
if (file.name.contains('$$')) {
file.renameTo(file.path.replace('$$', '$'))
}
}
}
}