gradle很好用,但是默认是没有代码覆盖功能的,只好自己写。曾经在网上找到过别人的一段脚本,虽然也能用,但是有一些不爽的地方,一个原因是它不支持对层级工程中全部代码的覆盖,另一个原因是它用替换build/classes/main里面的class文件,再依赖gradle的单元方式来实现的。我自己写了一个代码覆盖的脚本,可以避免这两个问题,代码如下:

allprojects {
apply plugin:'idea'
}
subprojects {
apply plugin:'java'
apply plugin:'eclipse'
apply plugin:'maven'
apply plugin:'project-report'
sourceCompatibility = 1.6
targetCompatibility = 1.6
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
dependencies {
runtime 'org.slf4j:slf4j-log4j12:1.4.2@jar'
testCompile 'junit:junit:4.8.2'
testCompile 'org.easymock:easymock:3.0'
testRuntime module('net.sourceforge.cobertura:cobertura:1.9.4') {
dependencies "asm:asm:3.1", "oro:oro:2.0.8", "asm:asm-tree:3.0"
}
testRuntime 'log4j:log4j:1.2.13'
testRuntime('org.apache.ant:ant-junit:1.8.2'){transitive = false}
}
/* START 代码覆盖 */
task runCover(dependsOn: testClasses) << {
def codeCoverDir = new File(buildDir, "codeCover")
def codeCoverClassesDir = new File(codeCoverDir, "classes")
def codeCoverTestReportDir = new File(codeCoverDir, "testReport")
def codeCoverDataFile = new File(codeCoverDir, "cobertura.ser")
def originalClassesDir = new File(buildDir, "classes/main")
def unitTestClassesDir = new File(buildDir, "classes/test")
def projectPath = project.path
ant {
delete(dir: codeCoverDir, failonerror:false)
mkdir(dir: codeCoverDir)
mkdir(dir: codeCoverClassesDir)
mkdir(dir: codeCoverTestReportDir)
if (!unitTestClassesDir.exists()) {
mkdir(dir: unitTestClassesDir)
}
taskdef(resource:'tasks.properties', classpath: configurations.testRuntime.asPath)
taskdef(name: 'junit', classname: 'org.apache.tools.ant.taskdefs.optional.junit.JUnitTask',
classpath: configurations.testRuntime.asPath)
copy(todir: codeCoverClassesDir) {
fileset(dir: originalClassesDir)
}
logger.lifecycle("cobertura-instrument: ${projectPath}")
'cobertura-instrument'(datafile:codeCoverDataFile) {
fileset(dir: codeCoverClassesDir, includes:"**/*.class")
}
logger.lifecycle("junit: ${projectPath}")
junit(haltonfailure: true, showoutput: true, fork: true, forkmode:'once') {
sysproperty(key: "net.sourceforge.cobertura.datafile", value: codeCoverDataFile)
classpath {
pathelement(path: configurations.testRuntime.asPath)
pathelement(location: codeCoverClassesDir)
pathelement(location: unitTestClassesDir)
}
formatter(type: 'plain')
batchtest(todir: codeCoverTestReportDir) {
fileset(dir: unitTestClassesDir, includes: "**/*Test.class")
}
}
}
}
task reportCover(dependsOn: runCover) << {
def codeCoverDir = new File(buildDir, "codeCover")
def codeCoverReportDir = new File(codeCoverDir, "coverReport")
def codeCoverDataFile = new File(codeCoverDir, "cobertura.ser")
ant {
mkdir(dir: codeCoverReportDir)
taskdef(resource:'tasks.properties', classpath: configurations.testRuntime.asPath)
'cobertura-report'(destdir: codeCoverReportDir, format:'html', datafile:codeCoverDataFile, encoding:'utf8') {
fileset(dir: "${projectDir}/src/main/java", includes: "**/*.java")
}
}
}
/* END */
}
/**
* 在根目录的build/codeCover/coverReport目录里生成整个工程的代码覆盖报告。必须至少有一个子工程存在,才能正常执行
*/
task reportCoverAll(dependsOn: subprojects.collect{"${it.path}:runCover"}) << {
def codeCoverDir = new File(buildDir, "codeCover")
def codeCoverReportDir = new File(codeCoverDir, "coverReport")
def codeCoverDataFile = new File(codeCoverDir, "cobertura.ser")
ant {
mkdir(dir: codeCoverReportDir)
taskdef(resource:'tasks.properties', classpath: subprojects.toArray()[0].configurations.testRuntime.asPath)
'cobertura-merge'(datafile: codeCoverDataFile) {
fileset(dir: rootDir, includes: "*/build/codeCover/cobertura.ser")
}
'cobertura-report'(destdir: codeCoverReportDir, format:'html', datafile:codeCoverDataFile, encoding:'utf8') {
subprojects.each {
fileset(dir: "${it.projectDir}/src/main/java", includes: "**/*.java")
}
}
}
}

实现的思路就是在每个子工程的build目录下生成codeCover目录,然后把testClasses生成的被测试的代码通过cobertura加工到这个目录下的子目录,再调用junit测试,最后生成报告,与gradle java插件里面的test任务没有任何关系。根工程里面的reportCoverAll可以把各子工程生成的cobertura.ser文件合并,生成统一的报告。

This work, unless otherwise expressly stated, is licensed under a ​​Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License​​.