Jacoco单元和集成测试覆盖范围 - 个人和整体

Aru*_*gal 5 integration-testing unit-testing code-coverage gradle jacoco

我有一个项目(ProjectA),其中包含一些单元测试和集成测试.

以下是结构.

ProjectA - src/java(java源代码)
- test/java(Junit单元测试)
- 测试/资源(Junit单元测试所需的资源)
- src/java-test(集成测试)
- conf(包含.xml所需的文件)建筑/测试/编制目的)

我运行以下命令 - 所有这些命令都有效,但我怀疑build.gradle/GRADLE_HOME/init.d/*.gradle文件中的配置如何影响我所获得的.

好像我错过了一些东西而没有得到我想要的东西.

命令:
- gradle clean build - 它工作正常
- gradle clean build jacocoTestReport - 它工作正常.
- gradle clean build IntegrationTest jacocoTestReport - 它工作正常(如果我有一个tomcat实例并在同一个ProjectA的另一个putty窗口中运行).

第三个子弹操作完成后,我在Jenkins作业工作区中看到额外的文件夹"build"及其子文件夹(除了从源/版本控制中检出的文件夹).

ie under - JenkinsWorkspace
/ build
- classes(包含以下提到的.class文件作为sourceSets部分之一)
---- integrationTest
---- main
---- test

- resources(包含所有文件) .这是在"CONF"文件夹中的源代码控制的.properties/.xml文件

- 报告(包含.XML/.html文件的PMD /的CheckStyle/FindBugs的和任一个单元测试结果或IT测试,但不能同时使用)---. - checkstyle
---- findbugs
---- pmd
---- jacoco
---- tests(注意:这是复数,即它不是"test",它被定义为sourceSets中的一个条目)

- jacoco(这包含2个.exec文件,即test.exec和integrationTest.exec都有不同的文件大小)
---- test.exec
---- integrationTest.exec

- jacocoHtml(这个文件夹包含很多文件夹(包含.html)文件)并且主要是"index.html"
.---- somexxxfolders
---- ---- somexxfolder's.html文件
---- index.html
----其他等文件/文件夹

- test-results(这包含一些.xml文件,但仅适用于单元测试或集成测试 - 但不适用于给定时间的两种测试类型).

即如果我运行"gradle clean build",那么你将看到与单元测试相关的.xml文件,如果我运行"gradle clean build integrationTest",那么单元测试.xml文件将被覆盖,我看到的.xml文件只是相关的由IntegrationTest任务生成/生成.


以下是常见的gradle之一(GRADLE_HOME/init.d/some.common.gradle文件)

//
//Extra file can hold global Gradle settings so that these dont have to be inserted in project
//specific build.gradle file.
//Filename: extraN.common<anyname>.gradle
allprojects {
   apply plugin: 'java'
   apply plugin: 'pmd'
   apply plugin: 'findbugs'
   apply plugin: 'checkstyle'
   apply plugin: 'jacoco'
   apply plugin: 'sonar-runner'
   tasks.withType(Compile) {
     options.debug = true
     options.compilerArgs = ["-g"]
   }
   sourceSets {
      main {
         java {
            // MOTE: If your project's build.gradle specify the sourceSet section, the following
            // values will be overwritten by what project's build.gradle will set.
            //
            // If you project's sourceSet structure if different in each project, then in this
            // global common .gradle file, you can define srcDir for main or other sections like
            // test, integrationTest etc as shown below -- commented out. If that's the case, 
            // then uncomment the below line and comment out using // -- srcDir 'src/java' line
            // for sourceSets.main.java section. This rule applies to other sections as well.
            // srcDir 'no_src_dir_set_yet'

            srcDir 'src/java'
         }
         resources {
            srcDir 'conf'
         }
      }
      test {
         java {
            srcDir 'test/java'
         }
         resources {
            srcDir 'test/resources'
            srcDir 'conf'
         }
      }
      integrationTest {
         java {
            srcDir 'src/java-test'
         }
         resources {
            srcDir 'conf'
         }
      }
   }
   def sonarServerUrl = "dev.sandbox.server.com"
   sonarRunner {
      sonarProperties {
         property "sonar.host.url", "http://$sonarServerUrl:9000"
         property "sonar.jdbc.url", "jdbc:h2:tcp://$sonarServerUrl:9092/sonar"
         property "sonar.jdbc.driverClassName", "org.h2.Driver"
         property "sonar.jdbc.username", "sonar"
         property "sonar.jdbc.password", "sonar"
         properties ["sonar.sources"] += sourceSets.main.allSource.srcDirs
         //properties ["sonar.tests"] += sourceSets.test.java.srcDirs
         properties ["sonar.tests"] += sourceSets.integrationTest.allSource.srcDirs
      }
   }
   checkstyle {
        configFile = new File(rootDir, "config/checkstyle.xml")
        ignoreFailures = true
        //sourceSets = [sourceSets.main, sourceSets.test, sourceSets.integrationTest]
        sourceSets = [sourceSets.main]
   }
   findbugs {
        ignoreFailures = true
        sourceSets = [sourceSets.main]
   }
   pmd {
        ruleSets = ["basic", "braces", "design"]
        ignoreFailures = true
   }
   jacoco {
      toolVersion = "0.6.2.201302030002"
      reportsDir = file("$buildDir/customJacocoReportDir")
   }
   task testReport(type: TestReport) {
      destinationDir = file("$buildDir/reports/allTests")
   }
   test {
        jacoco {
            //destinationFile = file("$buildDir/jacoco/jacocoTest.exec")
            destinationFile = file("$buildDir/jacoco/test.exec")
            //classDumpFile = file("$buildDir/jacoco/classpathdumps")
            classDumpFile = file("$buildDir/build/classes/test")
        }
   }
   jacocoTestReport {
         group = "Reporting"
         description = "Generate Jacoco coverage reports after running tests."
         reports {
                xml{
                    enabled true
                    destination "${buildDir}/reports/jacoco/jacoco.xml"
                }
                csv.enabled false
                html{
                    enabled true
                    destination "${buildDir}/jacocoHtml"
                }
        }
        additionalSourceDirs = files(sourceSets.main.allJava.srcDirs)
        //additionalSourceDirs = files([sourceSets.main.allJava.srcDirs, xxxx, 'xxxxyyyy' ])
   }
}
Run Code Online (Sandbox Code Playgroud)

build.gradle文件看起来像:

import com.tr.ids.gradle.CustomFileUtil
apply plugin: 'CustomSetup'
apply plugin: 'java'
apply plugin: 'customJarService'
apply plugin: 'customWarService'
sourceSets {
   main {
      java {
         srcDir 'src/java'
      }
   }
   test {
      java {
         srcDir 'test/java'
      }
      resources {
         srcDir 'test/resources'
         srcDir 'conf'
      }
   }
   integrationTest {
      java {
         srcDir 'src/java-test'
      }
   }
}
// Read dependency lists from external files. Our custom plugin reads a dep-xxx.txt file for compile/test/war related .jar file entries
// where each entry is like: groupid:artifactid:x.x.x
// and these artifact jars are available in Artifactory
List depListCompile = customFileUtil.readIntoList( "$projectDir/dep-compile.txt" )
List depListTest = customFileUtil.readIntoList( "$projectDir/dep-testArtifacts.txt" )
List depListWar = customFileUtil.readIntoList( "$projectDir/dep-war.txt" )
// Define dependencies
dependencies {
   // Compilation
   compile  depListCompile
   // Unit Tests
   testCompile depListTest
   // Integration tests
   // Everything from compile and testCompile targets
   integrationTestCompile configurations.compile
   integrationTestCompile configurations.testCompile
   // Output of compiling "main" files
   integrationTestCompile sourceSets.main.output
   // Additional dependencies from war and others
   integrationTestCompile depListTest, depListWar
   // All configuration files
   integrationTestRuntime files( 'conf' )
}
task deployTomcat( type: Copy, dependsOn: [ jar, compileIntegrationTestJava, warService ] ) {
   from "$buildDir/customWar/${project.name}.war"
   into "$projectDir/tomcat/webapps"
}
build {
  dependsOn deployTomcat
}
task integrationTest( type: Test, dependsOn: cleanTest ) {
   jacoco {
      //destinationFile = file("$buildDir/jacoco/jacocoTest.exec")
      destinationFile = file("$buildDir/jacoco/integrationTest.exec")
      //classDumpFile = file("$buildDir/jacoco/classpathdumps")
      classDumpFile = file("$buildDir/classes/integrationTest")
   }
   testClassesDir = sourceSets.integrationTest.output.classesDir
   classpath = sourceSets.integrationTest.runtimeClasspath
}
apply plugin: 'eclipse'
eclipse.classpath {
   // Define output directory so Eclipse does not accidentally clobber /bin
   defaultOutputDir = file( 'out/classes' )
   // Add integration test
   plusConfigurations += configurations.integrationTestCompile
   // Remove unnecessary files
   file.whenMerged { classpath ->
      classpath.entries.removeAll { entry -> ( entry.path.indexOf( '/build/classes/main' ) > 0 ) }
      classpath.entries.removeAll { entry -> ( entry.path.indexOf( '/build/resources/main' ) > 0 ) }
   }
}
Run Code Online (Sandbox Code Playgroud)

我的问题:

1)为什么"gradle clean build integrationTest" - 成功运行,会覆盖构建/报告/测试和构建/测试结果文件夹中的测试结果.

2)无论我在.comc文件下为普通gradle文件提供什么名称进行测试,在build.gradle中为jacoco的integrationTest任务,它始终创建test.exec和integrationTest.exec文件,但生成的build/jacocoHtml文件夹index.html文件不显示与单元/集成测试相关的coverage /文件.为了证明这一点,如果我运行"gradle clean build IntegrationTest jacocoTestReport sonarRunner",我会看到作业的工作区,现在包含".sonar"文件夹和build/reports/sonar文件夹,其中包含另一个名为"overall-xxx.exec"的文件"某些文件,但该文件大小不接近Unit test.exec和IT integrationTest.exec文件大小的"总和".虽然它比test.exec文件大小少了几个字节.

3)我可以设置什么配置来对Unit和IT测试进行全面覆盖,即整体... exec文件获得良好的大小(在运行sonarRunner任务之后).在sonarRunner任务期间,我确实看到SonarRunner任务的"jacocoSensor步骤"确实同时看到UT和IT .exec文件以及整个.exec文件(Sonar的一个很好的功能).

Aru*_*gal 4

找到我的第二个问题的答案。高级信息:

  1. Gradle 1.6 jacocoTestReport 使用不同的变量,Gradle >=1.7 使用不同的变量。

    例如:我们可以通过使用正确的变量更改“test”或“integrationTest”任务来调整单元测试和集成测试.exec文件的创建 - 否则它将无法生成“test.exec”和“integrationTest.exec”默认文件名称。请参阅下面的示例。

task IntegrationTest(type: Test) OR test { ... } 部分可以为我们正在使用的给定 Gradle 版本提供正确的变量。

task integrationTest (type: Test) { 
testClassesDir = sourceSets.integrationTest.output.classesDir

classpath = sourceSets.integrationTest.runtimeClasspath

   testReportDir = file("$buildDir/reports/tests/IT")
   testResultsDir = file("$buildDir/test-results/IT")



  ignoreFailures = true
   jacoco {

 //This works with 1.6
 destPath = file("$buildDir/jacoco/IT/jacocoIT.exec")
 classDumpPath = file("$buildDir/jacoco/IT/classpathdumps")

 /*
 Following works only with versions >= 1.7 version of Gradle
 destinationFile = file("$buildDir/jacoco/IT/jacocoIT.exec")
 classDumpFile = file("$buildDir/jacoco/IT/classpathdumps")
 */
   }
}
Run Code Online (Sandbox Code Playgroud)

同样,对于 test { .... } 任务,您可以将其定义为 ../../UT/jacocoUT.exec 和 ../../UT/classpathdumps...

  1. 如果我在项目工作区中运行“sonar-runner”Linux/Unix sonar-runner 可执行文件,则会创建 .sonar 文件夹,但是如果我运行调用 Gradle“clean buildintegrationTest jacocoTestReport sonarRunner”的 Jenkins 作业,则会创建 build/sonar 文件夹并成为 SONAR 的工作目录(这在输出期间显示)。

  2. 在 Jenkins > 构建后部分下,我提到了以下内容,现在,Jenkins 仪表板上的 jacoco 文件(.html 和 .xml)的 jacoco 代码覆盖率报告 - 包括单元和集成测试代码覆盖率数据。

Jenkins 中记录 Jacoco 覆盖率报告部分有以下框:

我提到:

执行文件的路径:/build/jacoco/UT/jacocoUT.exec,* /build/jacoco/IT/jacocoIT.exec 类目录的路径:* /build/jacoco/ /classpathdumps/com/thc (这是其中的位置Jacoco 检测类坐).. build/jacoco/UT/classpathdumps/com/thc 和 build/jacoco/IT/classpathdumps/com/thc 都将被选择为 ** 将被替换为 build/jacoco 下的任何文件夹。该值也可以设置为“build/classes”文件夹。

源文件的路径:**(如果我使用 src/java,源文件的一些链接不起作用,即文件内容不显示).. 使用 ** .. 现在可以使用。

休息箱 - 留空。

  1. 仍然想知道 - 为什么总体 jacoco.exec 没有文件大小 = jacocoUT.exec 和 jacocoIT.exec 的总和

此时,我可以看到单元测试和集成测试的 Jacoco 代码覆盖率,即通过访问作业仪表板上的 Jacoco 代码覆盖率图像并访问源代码链接,并且如果您去浏览“build/reports/jacoco/html” /index.html”或“build/jacocoHtml/index.html”文件。

仍在尝试找出 - SONAR 需要做什么来选择这 2 个 .exec 文件(我为 UT / IT exec 文件的源、测试、二进制文件、...reportsPath 等的 sonar.xxx variurs 变量设置了有效值...在 SonarQube 仪表板上,单元测试覆盖率显示良好,但集成测试覆盖率仍然为 0.0%。

我很快就会粘贴我的 common.gradle 和项目的 build.gradle 文件的副本......以便更好地查看。