Task 'testFlvDebugUnitTestCoverage' not found in root project 'src'

android

(Hesam) #1

Hi, I am trying to add Jacoco, code coverage report, into my Android project.
As this is long file, I try to put some related parts.
Although I am able to successfully run following command on my laptop, Bitrise CI complains that:

Task ‘testFlvDebugUnitTestCoverage’ not found in root project ‘src’.

This command is being executed on Bitrise:

$ ./gradlew “–build-file” “build.gradle” “testFlvDebugUnitTestCoverage” “–continue” “–stacktrace”

So, any idea would be appreciated.

Architecture of my app looks like:

-\ passenger-android
---- build.gradle
---- jacoco.gradle
---- setings.gradle
----\ passenger-app
-------- build.gradle
----\ passenger-sdk (this is library for passenger-app)
-------- build.gradle

This is what I have in build.gradle file of passenger-app:

apply plugin: 'com.android.application'
android androidConfiguration
apply plugin: 'io.fabric'
apply plugin: 'com.getkeepsafe.dexcount'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.neenbedankt.android-apt'
apply from: "$rootDir/jacoco.gradle"

android {
....
    buildTypes {
        debug {
            testCoverageEnabled = true
    }
....
}

This is what I have in build.gradle file of passenger-sdk:

apply plugin: 'com.android.library'
android androidConfiguration
apply plugin: 'com.neenbedankt.android-apt'
apply from: "$rootDir/jacoco.gradle"

android {
....
}

This is what I have in build.gradle file in root of project:

buildscript {
    repositories {
        jcenter()
        maven { url 'https://maven.fabric.io/public' }
        maven { url 'http://maven.apptimize.com/artifactory/repo' }
        maven { url 'https://zendesk.artifactoryonline.com/zendesk/repo' }
        maven { url "http://www.leanplum.com/leanplum-sdks/" }
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'
        classpath 'io.fabric.tools:gradle:1.22.0'
        classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.6.2'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
        classpath 'com.google.gms:google-services:3.0.0'
    }
}

ext {
    androidConfiguration = {
        sourceSets {
            main {
                manifest.srcFile 'src/main/AndroidManifest.xml'
                java.srcDirs = ['src/main/java']
                resources.srcDirs = ['src/main/resources']
                aidl.srcDirs = ['src/main/java']
                renderscript.srcDirs = ['src/main/java']
                res.srcDirs = ['src/main/res']
                assets.srcDirs = ['src/main/assets']
            }
        }

        testOptions {
            unitTests.all {
                jacoco {
                    includeNoLocationClasses = true
                }
            }
        }
    }
}

And Finally this is my jacoco.gradle file:

import java.util.regex.Pattern

apply plugin: 'jacoco'

/**
 * Jacoco is test coverage tool.
 *
 * Latest version can be found at following link but be careful upgrading — 
 * the latest version may not be compatible yet, resulting in quirks like empty coverage reports.
 * https://bintray.com/bintray/jcenter/org.jacoco:org.jacoco.core
 *
 * You can run the test via following command:
 * $./gradlew testFlvDebugUnitTestCoverage
 */

jacoco {
    toolVersion = "0.7.9"
}

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") {
                group = "Reporting"
                description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
                classDirectories = fileTree(
                        dir: "${project.buildDir}/intermediates/classes/${sourcePath}",
                        excludes: [
                                '**/R.class',
                                '**/R$*.class',
                                '**/*$ViewInjector*.*',
                                '**/*$ViewBinder*.*',
                                '**/BuildConfig.*',
                                '**/Manifest*.*',
                                // ignore ButterKnife generated code
                                '**/**$ViewBinder*.class',
                                // ignore Dagger 2 generated code
                                '**/Dagger*.class',
                                '**/**_MembersInjector*.class',
                                '**/**Module_*.class',
                                '**/**_Factory*.class',
                                // ignore AutoValue classes
                                '**/*AutoValue_*.class',
                                // ignore AutoValueGson classes
                                '**/AutoValueGson_*.class',
                                // ignore RxJava Closure classes
                                '**/**AjcClosure**.class',
                                // ignore eventbus
                                '**/AppEventBusIndex.class',
                                // ignore MyApp classes
                                'com/flv1/passenger/BuildConfigHelper.class',
                                'com/flv1/passenger/di/**',
                                'com/flv2/passenger/BuildConfigHelper.class',
                                'com/flv2/passenger/di/**',
                                '**/*Constants.class'
                        ]
                )

                def coverageSourceDirs = [
                        "src/main/java",
                        "src/$productFlavorName/java",
                        "src/$buildTypeName/java"
                ]
                additionalSourceDirs = files(coverageSourceDirs)
                sourceDirectories = files(coverageSourceDirs)
                executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")

                reports {
                    xml.enabled = true
                    html.enabled = true
                }

                doLast {
                    println "csv report has been generated to file://${reports.csv.destination}"
                    println "xml report has been generated to file://${reports.xml.destination}"
                    println "html report has been generated to file://${reports.html.destination}/index.html"
                    printTotalCoverageFromHtml(new File("${reports.html.destination}/index.html"))
                }
            }
        }
    }
}

// prints total coverage to console
void printTotalCoverageFromHtml(File file) {
    def html = file.getText();
    def instructionsPattern = Pattern.compile(">([\\d\\,]+)\\sof\\s([\\d\\,]+)<")
    def matcher = instructionsPattern.matcher(html)
    matcher.find()
    def missed = matcher.group(1)
    def total = matcher.group(2)
    def percentsPattern = Pattern.compile(">([\\d]+)%<")
    matcher = percentsPattern.matcher(html)
    matcher.find()
    def percents = matcher.group(1)
    def covered = Integer.parseInt(total.replace(",", "")) - Integer.parseInt(missed.replace(",", ""))
    println("Coverage: total instructions ${covered}/${total} - ${percents}%")
}