Покрытие тестового кода Android с помощью плагина JaCoCo Gradle

Я новичок в тестировании Gradle и Android, но я уже конвертировал свой проект Android для сборки с Gradle.

Сейчас я пытаюсь выполнить тестовое покрытие проекта Android с помощью плагина Gradle JaCoCo.

Я добавил следующее в мой файл build.gradle:

apply plugin: 'jacoco'

И когда я запускаю "gradle jacocoTestReport" следующую ошибку:

Task 'jacocoTestReport' not found in root project '<project name>'.

Из документации я должен также применить плагин "Java", но он конфликтует с плагином "Android".

Это можно обойти?

Заранее спасибо.

4 ответа

Решение

Вот как я пользуюсь Jacoco:

buildscript {
  repositories {
    mavenLocal()
    mavenCentral()
  }
  dependencies {
    classpath 'com.android.tools.build:gradle:0.12.+'
    classpath 'org.robolectric:robolectric-gradle-plugin:0.11.+'
  }
}

apply plugin: 'com.android.application'
apply plugin: 'robolectric'
apply plugin: 'jacoco'

android {
  compileSdkVersion 20
  buildToolsVersion "20.0.0"

  defaultConfig {
    applicationId "YOUR_PACKAGE_NAME"
    minSdkVersion 10
    targetSdkVersion 20
    testHandleProfiling true
    testFunctionalTest true
  }
  buildTypes {
    debug {
      testCoverageEnabled false
    }
    release {
      runProguard false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
    }
  }
  jacoco {
    version "0.7.1.201405082137"
  }
  packagingOptions {
    exclude 'META-INF/DEPENDENCIES.txt'
    exclude 'META-INF/LICENSE.txt'
    exclude 'META-INF/NOTICE.txt'
    exclude 'META-INF/NOTICE'
    exclude 'META-INF/LICENSE'
    exclude 'META-INF/DEPENDENCIES'
    exclude 'META-INF/notice.txt'
    exclude 'META-INF/license.txt'
    exclude 'META-INF/dependencies.txt'
    exclude 'META-INF/LGPL2.1'
    exclude 'META-INF/services/javax.annotation.processing.Processor'
    exclude 'LICENSE.txt'
  }
}

robolectric {
  include '**/*Test.class'
  exclude '**/espresso/**/*.class'

  maxHeapSize "2048m"
}

jacoco {
  toolVersion "0.7.1.201405082137"
}

// Define coverage source.
// If you have rs/aidl etc... add them here.
def coverageSourceDirs = [
    'src/main/java',
]

task jacocoTestReport(type: JacocoReport, dependsOn: "connectedDebugAndroidTest") {
  group = "Reporting"
  description = "Generate Jacoco coverage reports after running tests."
  reports {
    xml.enabled = true
    html.enabled = true
  }
  classDirectories = fileTree(
      dir: './build/intermediates/classes/debug',
      excludes: ['**/R*.class',
                 '**/*$InjectAdapter.class',
                 '**/*$ModuleAdapter.class',
                 '**/*$ViewInjector*.class'
      ])
  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('$$', '$'))
      }
    }
  }
}


dependencies {
  androidTestCompile('junit:junit:4.11') {
    exclude module: 'hamcrest-core'
  }
  androidTestCompile('org.robolectric:robolectric:2.3') {
    exclude module: 'classworlds'
    exclude module: 'maven-artifact'
    exclude module: 'maven-artifact-manager'
    exclude module: 'maven-error-diagnostics'
    exclude module: 'maven-model'
    exclude module: 'maven-plugin-registry'
    exclude module: 'maven-profile'
    exclude module: 'maven-project'
    exclude module: 'maven-settings'
    exclude module: 'nekohtml'
    exclude module: 'plexus-container-default'
    exclude module: 'plexus-interpolation'
    exclude module: 'plexus-utils'
    exclude module: 'wagon-file'
    exclude module: 'wagon-http-lightweight'
    exclude module: 'wagon-http-shared'
    exclude module: 'wagon-provider-api'
    exclude group: 'com.android.support', module: 'support-v4'
  }
}

Приведенный выше код также содержит обходной путь для https://code.google.com/p/android/issues/detail?id=69174.

Более подробная информация: http://chrisjenx.com/gradle-robolectric-jacoco-dagger/

Я использую JaCoCo с проектом, использующим RoboGuice, Butterknife и Robolectric. Мне удалось настроить его с помощью решения @Hieu Rocker, однако были некоторые незначительные недостатки, т. Е. В нашем проекте мы использовали разновидности и у нас есть несколько дополнительных тестов для этих разновидностей, а также дополнительный Java-код для каждого из них. Мы также используем разные типы сборки. Поэтому решение, основанное на задаче testDebug, оказалось недостаточно хорошим. Вот мое решение: в build.gradle в модуле приложения добавьте

apply from: '../app/jacoco.gradle'

Затем создайте файл jacoco.gradle внутри модуля приложения со следующим содержимым:

    применить плагин: 'jacoco'

    jacoco {
        toolVersion "0.7.1.201405082137"
    }

    def getFlavorFromVariant(String variableName) {
        def flavourString = variableName.replaceAll(/(.*)([AZ].*)/) {все, flavName, buildTypeName ->
           flavourName
        }
        return flavourString;
    }

    def getBuildTypeFromVariant(String variableName) {def buildTypeString = variableName.replaceAll(/(.*)([AZ].*)/) { all, flavName, buildTypeName ->
            "${buildTypeName.toLowerCase()}"
        } вернуть buildTypeString;
    }

    def getFullTestTaskName(String variableName) {
        return "test${variableName.capitalize()}UnitTest";
    }

    android.applicationVariants.all {option ->
        def variableName = variable.name; def flavourFromVariant = getFlavorFromVariant ("$ {variableName}"); def buildTypeFromVariant = getBuildTypeFromVariant ("$ {variableName}");
        def testTaskName = getFullTestTaskName("${variableName}")

        task ("jacoco${variableName.capitalize()}TestReport", тип: JacocoReport, depenOn: testTaskName) {
            group = "Reporting"
            description = "Создание отчетов покрытия JaCoCo после выполнения тесты для варианта: ${variableName}. " reports {xml.enabled = true html.enabled = true} classDirectories = fileTree (dir: "./build/intermediates/classes/$ndomflavorFromVariant‹/$ndombuildTypeFromVariant}", исключая: ['**/R*.class',
                               '**/*$InjectAdapter.class',
                               '**/*$ModuleAdapter.class',
                               '**/*$ViewInjector*.class'
                    ])

            logger.info("Настройка JaCoCo для флейвора: ${flavourFromVariant" }, buildType: ${buildTypeFromVariant}, задача: ${testTaskName}");

            def coatingSourceDirs = [
                    '../app/src/main/java',
                    "../app/src/$ndomflavorFromVariant‹/java"
            ]
            sourceDirectories = files(coverSourceDirs)
            executeData = files("$buildDir/jacoco/${testTaskName}.exec")
            // Немного странно, но исправляет https://code.google.com/p/android/issues/detail?id=69174.
            // Итерируем скомпилированное дерево.class и переименовываем $$ в $.
            doFirst {новый файл ("$ buildDir / промежуточные / классы /").eachFileRecurse { file ->
                    if (file.name.contains('$$')) {
                        file.renameTo(file.path.replace('$$'), '$'))
                    }
                }
            }
        }
    }

Вы можете выполнить его из командной строки следующим образом:

.gradlew jacocoFlavor1DebugTestReport

или же

.gradlew jacocoOtherflavorPrereleaseTestReport

В нашем проекте мы используем соглашение не использовать заглавную букву внутри имен разновидностей и типов сборки, но если ваш проект не следует этому соглашению, вы можете просто изменить функции getFlavorFromVariant(..) и getBuildTypeFromVariant(..)

Надеюсь, это поможет кому-то

Вы можете попробовать использовать этот плагин Gradle: https://github.com/arturdm/jacoco-android-gradle-plugin

В ответе есть еще немного /questions/5621945/kodovoe-pokryitie-jacoco-i-modulnyih-testov-s-pomoschyu-android-gradle-plugin-11/5621963#5621963.

Вы пытались добавить следующее:

jacocoTestReport {
   group = "Reporting"
   description = "Generate Jacoco coverage reports after running tests."
   additionalSourceDirs = files(sourceSets.main.allJava.srcDirs)
}

И тогда вместо запуска ./gradlew jacocoTestReport бежать ./gradlew test jacocoTestReport,

Если все идет хорошо, вы должны найти результаты теста на build/reports/jacoco/test/html/index.html,

Другие вопросы по тегам