Jacoco и Unit Tests Code Coverage с android- gradle -plugin >= 1.1
Недавно я начал интегрировать android-gradle-plugin
1.1.0 в один из моих проектов. В проекте используется robolectric 2.4
для запуска модульных тестов.
Это проект с несколькими модулями с очень сложными зависимостями (некоторые модули зависят от других модулей). Что-то вроде этого:
--> application-module (dependsOn: module1, module2, module-core)
--> module1 (dependsOn: module-core)
--> module2 (dependsOn: module-core)
--> module-core (dependsOn: module3, module4)
--> module3 (library dependencies)
--> module4 (library dependencies)
Для более очищенного изображения см. проект jacoco-example.
Я попытался интегрировать JaCoCo для создания отчетов для модульных тестов, но мне кажется, что он работает только androidTests
, которые являются в основном инструментальными тестами.
После некоторых google'ing я столкнулся с несколькими проектами в GitHub и другими статьями, но в основном они ориентированы на предыдущие версии android-gradle-plugin
или используют другие сторонние плагины, такие как android-unit-test
например, здесь.
Возможно, я потерял способность Google. Но может кто-нибудь указать мне в направлении, где я могу найти документацию относительно нового материала в плагине android gradle и как запустить задачу jacoco только для модульных тестов?
UPDATE
Принял script из nenick example:
apply plugin: "jacoco"
configurations {
jacocoReport
}
task jacocoReport(dependsOn: 'testDebug') << {
ant {
taskdef(name:'jacocoreport',
classname: 'org.jacoco.ant.ReportTask',
classpath: configurations.jacocoReport.asPath)
mkdir dir: "${buildDir}/test-coverage-report"
mkdir dir: "${buildDir}/reports/jacoco/test/"
jacocoreport {
executiondata = files("${buildDir}/jacoco/testDebug.exec")
structure(name: "${rootProject.name}") {
classfiles {
fileset (dir: "${buildDir}/intermediates/classes/debug") {
//exclude(name: '**/*_*.class')
exclude(name: '**/R.class')
exclude(name: '**/R$*.class')
exclude(name: '**/BuildConfig.class')
}
}
sourcefiles {
fileset dir: "src/main/java"
fileset dir: "${buildDir}/generated/source/buildConfig/debug"
fileset dir: "${buildDir}/generated/source/r/debug"
}
}
xml destfile: "${buildDir}/reports/jacoco/test/jacocoTestReport.xml"
html destdir: "${buildDir}/test-coverage-report/"
}
}
}
dependencies {
jacocoReport 'org.jacoco:org.jacoco.ant:0.7.2.201409121644'
}
После этого ./gradlew jacocoReport
выполняет и генерирует отчет, но он показывает 0 (нулевое) охват теста, что невозможно, потому что тестируется по меньшей мере половина всех классов.
UPDATE_2
Пробовал этот пример. Добавление следующей задачи в один из моих файлов сборки gradle:
task jacocoTestReport(type:JacocoReport, dependsOn: "testDebug") {
group = "Reporting"
description = "Generate Jacoco coverage reports"
classDirectories = fileTree(
dir: "${buildDir}/intermediates/classes/debug",
excludes: ['**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/BuildConfig.*',
'**/Manifest*.*']
)
sourceDirectories = files("${buildDir.parent}/src/main/java")
additionalSourceDirs = files([
"${buildDir}/generated/source/buildConfig/debug",
"${buildDir}/generated/source/r/debug"
])
executionData = files("${buildDir}/jacoco/testDebug.exec")
reports {
xml.enabled = true
html.enabled = true
}
}
Такая же проблема, отчеты генерируются, но охват кода по-прежнему равен нулю.
UPDATE_3
Это означает, что задача из UPDATE_2 работала, но только для модуля с apply plugin: 'com.android.application'
(отчеты генерируются правильно). Но для модулей, которые являются библиотеками Android (apply plugin: 'com.android.library'
), отчеты показывают нулевое покрытие, хотя модули содержат больше тестов, чем программный модуль.
UPDATE_4
Создал простой пример, демонстрирующий мою проблему. В настоящее время, если вы запустите ./gradlew jacocoReport
, отчет создается, но для проектов модулей не отображается охват тестирования. См. Ссылку
Краткое примечание:. Когда тесты были AndroidUnitTests (whiteout JUnit 4 и Robolectric), отчеты JaCoCo показали покрытие для всех модулей.
Любые идеи?
Ответы
Ответ 1
После суеты я решил создать плагин с открытым исходным кодом Gradle для этого.
Root build.gradle
buildscript {
repositories {
mavenCentral() // optional if you have this one already
}
dependencies {
classpath 'com.vanniktech:gradle-android-junit-jacoco-plugin:0.8.0'
}
}
apply plugin: 'com.vanniktech.android.junit.jacoco'
Затем просто выполните
./gradlew jacocoTestReportDebug
Он запустит тесты JUnit в режиме отладки, а затем предоставит вам выход Jacoco в формате xml и html в соответствующем каталоге сборки.
Он также поддерживает ароматы. Имея 2 аромата красного и синего, эти задачи будут созданы
- jacocoTestReportRedDebug
- jacocoTestReportBlueDebug
- jacocoTestReportRedRelease
- jacocoTestReportBlueRelease
Ответ 2
После некоторого дополнительного поиска я наткнулся на этот проект
Я должен был внести некоторые изменения, чтобы решение могло работать для моего типа проекта, но теперь отчеты о охвате теста генерируются должным образом.
Я ввел принятые изменения в мой пример github repo, если у кого-то будет такая же проблема в будущем.
Ответ 3
Я устанавливаю свои модульные тесты для gradle 1.2, используя этот пост в блоге. Затем я собрал информацию, которую я нашел здесь и в других местах, чтобы добавить покрытие кода к независимым модулям вместо всего проекта. В моем библиотечном модуле build.gradle
я добавил следующее:
apply plugin: 'jacoco'
def jacocoExcludes = [
'com/mylibrary/excludedpackage/**'
]
android {
...
}
android.libraryVariants.all { variant ->
task("test${variant.name.capitalize()}WithCoverage", type: JacocoReport, dependsOn: "test${variant.name.capitalize()}") {
group = 'verification'
description = "Run unit test for the ${variant.name} build with Jacoco code coverage reports."
classDirectories = fileTree(
dir: variant.javaCompile.destinationDir,
excludes: rootProject.ext.jacocoExcludes.plus(jacocoExcludes)
)
sourceDirectories = files(variant.javaCompile.source)
executionData = files("${buildDir}/jacoco/test${variant.name.capitalize()}.exec")
reports {
xml.enabled true
xml.destination "${buildDir}/reports/jacoco/${variant.name}/${variant.name}.xml"
html.destination "${buildDir}/reports/jacoco/${variant.name}/html"
}
}
}
И в моем проекте build.gradle
файл, я добавил общие исключения:
ext.jacocoExcludes = [
'android/**',
'**/*$$*',
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Service.*'
]
Кроме того, похоже, что кодовое покрытие для модульных тестов может появиться в будущем Проблема 144664
Ответ 4
Предупреждение: Это взломать! Используя вашу конфигурацию выше, я собрал взломанный ключ для переключения плагина android между приложением и библиотекой в зависимости от выбранных задач сборки. Это хорошо работает для меня, потому что я не завершаю код с установленным режимом приложения.
// dynamically change the android plugin to application if we are running unit tests or test reports.
project.ext.androidPlugin = 'com.android.library'
for (String taskName : project.gradle.startParameter.taskNames) {
if (taskName.contains('UnitTest') || taskName.contains('jacocoTestReport')) {
project.ext.androidPlugin = 'com.android.application'
break
}
}
logger.lifecycle("Setting android pluging to ${project.ext.androidPlugin}")
apply plugin: project.ext.androidPlugin
...
apply plugin: 'jacoco'
configurations {
jacocoReport
}
task jacocoTestReport(type:JacocoReport, dependsOn: "testDebug") {
group = "Reporting"
description = "Generate Jacoco coverage reports"
classDirectories = fileTree(
dir: "${buildDir}/intermediates/classes/debug",
excludes: ['**/R.class',
'**/R$*.class',
'**/*$ViewInjector*.*',
'**/BuildConfig.*',
'**/Manifest*.*']
)
sourceDirectories = files("${buildDir.parent}/src/main/java")
additionalSourceDirs = files([
"${buildDir}/generated/source/buildConfig/debug",
"${buildDir}/generated/source/r/debug"
])
executionData = files("${buildDir}/jacoco/testDebug.exec")
reports {
xml.enabled = true
html.enabled = true
}
}
Надеемся, что команда разработчиков Android скоро это исправит.
Ответ 5
Наконец-то я смог увидеть мое покрытие кода JUnit-тестов в Android Studio 1.1.
jacoco.gradle
apply plugin: 'jacoco'
jacoco {
toolVersion "0.7.1.201405082137"
}
def coverageSourceDirs = [
"$projectDir/src/main/java",
]
task jacocoTestReport(type: JacocoReport, dependsOn: "testDebug") {
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('$$', '$'))
}
}
}
}
а затем в файле build.gradle модуля (я установил его между android
и dependencies
):
apply from: '../jacoco.gradle'
Также в блоке defaultConfig
android
. Я добавил это (не знаю, если это необходимо, но я получил это от этого блога):
android {
defaultConfig {
testHandleProfiling true
testFunctionalTest true
}
}
Enjoy.
Ответ 6
Я решаю проблемы с JaCoCo и делаю его работающим с последним gradle плагином Android 1.1.3
Проект с последними gradle скриптами: https://github.com/OleksandrKucherenko/meter
Литература:
Как подключить собственную реализацию вместо Mocks в Android Studio Unit Tests? https://plus.google.com/117981280628062796190/posts/8jWV22mnqUB
Небольшой намек для всех, кто пытается использовать покрытие JaCoCo в сборках Android, неожиданное открытие!!! https://plus.google.com/117981280628062796190/posts/RreU44qmeuP
JaCoCo XML/HTML-отчет для модульных тестов https://plus.google.com/u/0/+OleksandrKucherenko/posts/6vNWkkLed3b
Ответ 7
У меня была такая же проблема, как и вы. Сегодня я полностью удалил андроид-студию, android sdk, gradle. Затем переустановите все. После этого я просто добавил в приложение build.gradle.
debug { testCoverageEnabled true
}
Затем я запускаю. /gradlew connectedChec. Все работает отлично. Студия Android по умолчанию Jacoco отлично работает для меня. Я думаю, что также возможно создать jacocoTestReport Task, а затем создать покрытие кода. Я не знаю, почему gradle и андроид-студия ранее не работали.
Ответ 8
Вы можете использовать этот плагин Gradle:
https://github.com/arturdm/jacoco-android-gradle-plugin
В принципе, все, что вам нужно сделать, это применить его следующим образом:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.dicedmelon.gradle:jacoco-android:0.1.1'
}
}
apply plugin: 'com.android.library' // or 'com.android.application'
apply plugin: 'jacoco-android'
В результате вы должны получить задачу JacocoReport
для каждого варианта. Выполните приведенную ниже команду, чтобы генерировать отчеты о покрытии кода для всех из них.
$ ./gradlew jacocoTestReport
Ответ 9
Пожалуйста, создайте пример, и я могу посмотреть. Я предполагаю, что это недостающая конфигурация пути.
- включают все файлы покрытия (*.exec)
- добавить все исходные пути (module/src/main/java)
- добавить все пути к классам (модуль/сборка/промежуточные/классы/отладка)
вот два примера, как это выглядело