Java单元测试实践-00.目录(9万多字文档+700多测试示例)
https://blog.csdn.net/a82514921/article/details/107969340
1. Gradle单元测试日志、报告与JaCoCo代码覆盖率
1.1. Gradle单元测试日志
参考 https://docs.gradle.org/current/userguide/java_testing.html#sec:test_execution ,或 https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html#org.gradle.api.tasks.testing.Test:testLogging 。testLogging属性包含一组选项,用于控制记录哪些测试事件以及在记录的级别。还可以通过此属性配置其他日志记录行为。
该属性的类型为TestLoggingContainer,可参考 https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.logging.TestLoggingContainer.html , 或 https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/testing/logging/TestLoggingContainer.html 。
TestLoggingContainer的events属性用于指定需要记录日志的事件类型。events属性定义在TestLoggingContainer的父接口TestLogging中,可参考 https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/testing/logging/TestLogging.html#events-java.lang.Object…- 。
events属性可使用TestLogEvent枚举值,可参考 https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/testing/logging/TestLogEvent.html 。
TestLogEvent枚举值说明如下:
枚举常量 | 描述 |
---|---|
FAILED | 某个测试已失败 |
PASSED | 某个测试已成功完成 |
SKIPPED | 某个测试已跳过 |
STANDARD_ERROR | 某个测试在标准错误写入的信息 |
STANDARD_OUT | 某个测试在标准输出写入的信息 |
STARTED | 某个测试已开始 |
可将需要记录日志的事件设置为FAILED、PASSED、SKIPPED、STARTED,便于观察测试执行进度。STANDARD_ERROR与STANDARD_OUT会导致输出大量日志,因此不使用。如下所示:
test {
testLogging {
events "PASSED", "STARTED", "FAILED", "SKIPPED"
}
}
使用以上配置后,执行测试时,会输出测试类名、方法名,以及事件名称,输出的日志如下所示:
adrninistrator.test.testmock.custom_init_method.TestInitMethodSuppress > test1 PASSED
adrninistrator.test.testmock.custom_init_method.TestInitMethodSuppress > test2 STARTED
adrninistrator.test.testmock.custom_init_method.TestInitMethodSuppress > test2 PASSED
adrninistrator.test.testmock.custom_init_method.TestInitMethodSuppress > test3 STARTED
1.2. 生成测试报告
参考 https://docs.gradle.org/current/userguide/java_testing.html#test_reporting 。
Gradle执行test任务时,默认会生成以下结果:
- HTML格式的测试报告;
- XML格式测试结果的格式,与Ant JUnit报告任务兼容,许多其他工具(例如CI服务器)都支持该格式;
- 二进制格式高效的结果,可用于test任务生成其他格式。
- reports方法
参考 https://docs.gradle.org/current/dsl/org.gradle.api.tasks.testing.Test.html#org.gradle.api.tasks.testing.Test:reports 。
Gradle test任务中包含类型为TestTaskReports的属性reports。
参考TestTaskReports接口的API文档 https://docs.gradle.org/current/javadoc/org/gradle/api/tasks/testing/TestTaskReports.html ,其中包含以下方法:
返回类型 | 方法名称 | 说明 |
---|---|---|
DirectoryReport | getHtml() | 指示测试执行结果的HTML报告 |
JUnitXmlReport | getJunitXml() | JUnit XML格式的测试结果 |
通过以上可知,在Gradle test任务的reports方法中,可以指定html、junitXml属性的参数。
在Gradle test任务中使用以下代码查看reports方法的html、junitXml属性参数值:
test {
reports {
html {
println "destination: " + getDestination()
println "displayName: " + getDisplayName()
println "name: " + getName()
println "outputLocation: " + getOutputLocation()
println "outputType: " + getOutputType()
println "required: " + getRequired()
println "enabled: " + isEnabled()
}
junitXml {
println "destination: " + getDestination()
println "displayName: " + getDisplayName()
println "name: " + getName()
println "outputLocation: " + getOutputLocation()
println "outputType: " + getOutputType()
println "required: " + getRequired()
println "enabled: " + isEnabled()
}
}
}
执行结果如下所示:
destination: E:\UnitTest\build\reports\tests\test
displayName: Report generated by task ':test' (html)
name: html
outputLocation: Report html property 'outputLocation'
outputType: DIRECTORY
required: Report html property 'required'
enabled: true
destination: E:\UnitTest\build\test-results\test
displayName: Report generated by task ':test' (junitXml)
name: junitXml
outputLocation: Report junitXml property 'outputLocation'
outputType: DIRECTORY
required: Report junitXml property 'required'
enabled: true
可以看到HTML格式的测试报告生成目录为“build\reports\tests\test”,默认开启;XML格式的测试报告生成目录为“build\test-results\test”,默认开启。
使用setEnabled()、setDestination()方法设置报告生成是否开启、生成目录时执行失败,例如“setEnabled(true)”“setDestination(file("$buildDir/reports"))”,提示不允许修改,如“The value for Report html property ‘required’ is final and cannot be changed any further.”“The value for Report html property ‘outputLocation’ is final and cannot be changed any further.”。在Gradle 4.1版本中支持修改以上参数。
- HTML格式测试报告
HTML格式测试报告生成在“build\reports\tests\test”目录中,classes目录中保存了各个类的HTML格式测试结果,packages目录中保存了各个包的HTML格式测试结果。
打开index.html,可查看各个类的测试结果,测试耗时,标准输出日志,标准错误日志等,如下所示:
- XML格式测试报告
HTML格式测试报告生成在“build\test-results\test”目录中,每个类存在一个对应的XML文件,如下所示:
1.3. 使用JaCoCo生成代码覆盖率报告
参考 https://docs.gradle.org/current/userguide/jacoco_plugin.html#sec:jacoco_getting_started 。
使用JaCoCo插件可以计算代码覆盖率,添加JaCoCo插件可使用以下方式:
plugins {
id 'jacoco'
}
1.3.1. jacocoTestReport任务
参考 https://docs.gradle.org/current/userguide/jacoco_plugin.html#sec:jacoco_report_configuration 。
使用jacocoTestReport任务可以生成不同格式的代码覆盖率报告。
jacocoTestReport任务对应的类型为JacocoReport,可参考 https://docs.gradle.org/current/dsl/org.gradle.testing.jacoco.tasks.JacocoReport.html 、 https://docs.gradle.org/current/javadoc/org/gradle/testing/jacoco/tasks/JacocoReport.html 。
jacocoTestReport任务中包含reports()方法,类型为JacocoReportsContainer接口。
参考JacocoReportsContainer接口的API文档 https://docs.gradle.org/current/javadoc/org/gradle/testing/jacoco/tasks/JacocoReportsContainer.html ,其中包含以下方法:
返回类型 | 方法名称 | 说明 |
---|---|---|
SingleFileReport | getCsv() | JaCoCo的CSV格式报告 |
DirectoryReport | getHtml() | JaCoCo的HTML格式报告 |
SingleFileReport | getXml() | JaCoCo的XML格式报告 |
通过以上可知,在Gradle jacocoTestReport任务的reports方法中,可以指定csv、html、xml属性的参数。
例如通过以下配置,禁用csv、xml格式的报告,启用html格式报告,并指定报告生成目录:
jacocoTestReport {
reports {
xml.enabled = false
csv.enabled = false
html.enabled = true
html.destination = file("${buildDir}/jacocoReport")
}
}
参考 https://docs.gradle.org/current/userguide/jacoco_plugin.html#sec:jacoco_report_violation_rules ,可以检查代码覆盖率是否达到指定值。
1.3.2. 执行测试时生成代码覆盖率报告
在执行测试时,若需要生成代码覆盖率报告,需要同时指定test与jacocoTestReport任务,例如:
gradlew test jacocoTestReport
gradlew test -DtestMode=fast jacocoTestReport
test任务相关的参数需要在jacocoTestReport任务之前指定。
测试执行完毕后,经过一段时间代码覆盖率报告会生成。通过上述配置指定生成到“build/jacocoReport”目录时,如下所示:
以被测试代码包名命名的目录中,包含了对应的类的html格式的报告文件。
打开index.html后,可查看各类的代码覆盖率,如下所示:
1.3.2.1. 执行测试失败时生成代码覆盖率报告
参考 https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continue_build_on_failure 。
默认情况下,Gradle会在任何任务失败后中止执行并立即使构建失败。
当使用–continue选项执行时,Gradle不会在遇到第一个失败时立即停止,而是会执行依赖任务已成功完成的所有任务。每个遇到的失败都将在构建结束时报告。如果任务失败,则将不执行任何依赖于该任务的后续任务。
默认情况下,执行test与jacocoTestReport任务,若test任务失败,则jacocoTestReport任务不会执行。
为了使test任务执行出现失败时,jacocoTestReport任务也能执行,需要使用–continue选项,如下所示:
gradlew test jacocoTestReport --continue
1.3.3. 指定生成覆盖率报告的代码类范围
参考 https://docs.gradle.org/current/dsl/org.gradle.testing.jacoco.tasks.JacocoReport.html#org.gradle.testing.jacoco.tasks.JacocoReport:classDirectories ,JacocoReport类型中包含属性classDirectories,用于设置需要生成覆盖率报告的代码集,其类型为ConfigurableFileCollection。
参考ConfigurableFileCollection类型的API文档 https://docs.gradle.org/current/javadoc/org/gradle/api/file/ConfigurableFileCollection.html ,可通过setFrom()方法设置源代码路径。
可通过以下方式指定生成覆盖率报告的代码类范围,可参考示例项目unittest.gradle文件test任务(使用Groovy配置文件中的配置参数):
jacocoTestReport {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree('dir': it,
'include': ['com/adrninistrator/service/**', 'com/adrninistrator/applicationlistener/**'],
'exclude': ['**/TestPrivateNonVoidService1**'])
}))
}
可通过fileTree的include/exclude属性指定需要包含/排除的生成覆盖率报告的代码。
在Gradle 4.x版本(如4.1、4.7)中,需要使用以下方式指定生成覆盖率报告的代码类范围:
jacocoTestReport {
afterEvaluate {
classDirectories = files(classDirectories.files.collect {
fileTree('dir': it,
'include': ['com/adrninistrator/service/**', 'com/adrninistrator/applicationlistener/**'],
'exclude': ['**/TestPrivateNonVoidService1**'])
})
}
}
1.3.4. 覆盖率报告显示代码中文乱码问题
在Windows环境执行Gradle命令进行单元测试并生成代码覆盖率报告时,若不指定JVM的编码参数,生成的代码覆盖率报告中显示的代码中文会乱码,需要修改gradlew.bat脚本,在DEFAULT_JVM_OPTS参数中指定“"-Dfile.encoding=UTF-8"”。