2013-08-21 2 views
32

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

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

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

apply plugin: 'jacoco' 

И когда я бегу "Gradle jacocoTestReport" следующее сообщение об ошибке:

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

Из документации я должен также применять плагин «java», но он конфликтует с плагином «android».

Есть ли способ обойти это?

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

+0

Тестовое покрытие еще не поддерживается плагином-градиентом android. Я тоже ищу способ достичь, но теперь он выглядит безнадежным, поскольку плагин gradle для android не сообщает андроиду для создания любого покрытия. – Snicolas

+0

до тех пор, пока плагин java и плагин android не будут совместимы, вы можете использовать ant.java для выполнения тестов, а также создать отчет о покрытии. в основном делайте то, что вы сделали бы в ANT. – skipy

+2

@skipy: У вас есть пример того, как это сделать в муравье? Я не смог найти пример настройки jacocoagent и получения отчета от эмулятора. – unholysampler

ответ

22

Вот как я использую 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/

+0

Как вы интегрировали скрипт выше с Android-плагином? Можете ли вы дать мне ссылку, чтобы увидеть ваши файлы градиента? – Borys

+0

@Borys предполагает, что у вас уже есть 'build.gradle' с интегрированным robolectric. Вам просто нужно установить 'apply plugin: 'jacoco'' в разделе« применить плагин », а затем добавить оставшийся код выше в конец' build.gradle'. Затем вы можете запустить './gradlew testDebug jacocoTestReport'. Вот и все. –

+0

Hm .... Я получил следующую ошибку: «Не удалось определить зависимости задачи»: app: jacocoTestReport «Что я пропустил? – Borys

-3

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

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.

+1

Пробовал ваше решение, вот что я получаю: > Не удалось найти метод jacocoTestReport() для аргументов [build_5dkpq0odkgno9tsiihqqr1k86u $ _run_closure4 @ 49c96202] в проекте ': App'. – Egor

+1

Плагин jacoco не совместим с плагином Android. Плагин jacoco нуждается в проекте Java. – skyisle

+0

Итак, как запустить его в Android-проекте? – Borys

6

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

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

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

 

    apply plugin: 'jacoco' 

    jacoco { 
     toolVersion "0.7.1.201405082137" 
    } 

    def getFlavorFromVariant(String variantName) { 
     def flavorString = variantName.replaceAll(/(.*)([A-Z].*)/) { all, flavorName, buildTypeName -> 
      flavorName 
     } 
     return flavorString; 
    } 

    def getBuildTypeFromVariant(String variantName) { 
     def buildTypeString = variantName.replaceAll(/(.*)([A-Z].*)/) { all, flavorName, buildTypeName -> 
      "${buildTypeName.toLowerCase()}" 
     } 
     return buildTypeString; 
    } 

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

    android.applicationVariants.all { variant -> 
     def variantName = variant.name; 
     def flavorFromVariant = getFlavorFromVariant("${variantName}"); 
     def buildTypeFromVariant = getBuildTypeFromVariant("${variantName}"); 
     def testTaskName = getFullTestTaskName("${variantName}") 

     task ("jacoco${variantName.capitalize()}TestReport", type: JacocoReport, dependsOn: testTaskName) { 
      group = "Reporting" 
      description = "Generate JaCoCo coverage reports after running tests for variant: ${variantName}." 
      reports { 
       xml.enabled = true 
       html.enabled = true 
      } 

      classDirectories = fileTree(
        dir: "./build/intermediates/classes/${flavorFromVariant}/${buildTypeFromVariant}", 
        excludes: ['**/R*.class', 
           '**/*$InjectAdapter.class', 
           '**/*$ModuleAdapter.class', 
           '**/*$ViewInjector*.class' 
        ] 
      ) 

      logger.info("Configuring JaCoCo for flavor: ${flavorFromVariant}, buildType: ${buildTypeFromVariant}, task: ${testTaskName}"); 

      def coverageSourceDirs = [ 
        '../app/src/main/java', 
        "../app/src/${flavorFromVariant}/java" 
      ] 
      sourceDirectories = files(coverageSourceDirs) 
      executionData = files("$buildDir/jacoco/${testTaskName}.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('$$', '$')) 
        } 
       } 
      } 
     } 
    } 

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

.gradlew jacocoFlavor1DebugTestReport 

или

.gradlew jacocoOtherflavorPrereleaseTestReport 

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

Надеется, что это помогает кому-то

+4

Привет, Петр, я получаю Не удалось определить зависимости задачи ': app: jacocoDebugTestReport'. > Задача с путём 'testDebug' не найдена в проекте ': app'. любая идея почему? – AndroidGecko

+0

@AndroidGecko Я обновил ответ. Имя тестовой задачи теперь имеет «UnitTest», добавленное в конце. Надеюсь, поможет! –