16、测试与报告:单元测试(JUnit5/TestNG)、集成测试配置、测试报告生成(HTML/XML)
说实话,很多开发兄弟对测试的态度就是「能跑就行」。我以前也这么想,直到有一次线上出了个低级bug,查了半天发现是单元测试覆盖率太低。嗯,从那以后我再也不敢轻视测试了。
这一章,咱们就聊聊Gradle里的测试那些事。说白了,就是怎么让你的代码在提交之前就自己把自己检查一遍。
16.1 单元测试:JUnit5 与 TestNG
Gradle对测试框架的支持非常友好。你只需要在依赖里声明一下,剩下的交给它就好。
16.1.1 配置 JUnit5
我个人习惯用JUnit5,因为它比JUnit4更灵活,而且支持Lambda表达式。配置起来也很简单:
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}
test {
useJUnitPlatform()
}
你看,就两行。testImplementation表示这个依赖只在测试时使用,不会打包到生产环境。useJUnitPlatform()是告诉Gradle用JUnit5的引擎来跑测试。
写个简单的测试类:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
@Test
void testAdd() {
Calculator calc = new Calculator();
assertEquals(5, calc.add(2, 3));
}
@Test
void testDivideByZero() {
Calculator calc = new Calculator();
assertThrows(ArithmeticException.class, () -> calc.divide(1, 0));
}
}
这里有个小技巧:@DisplayName注解可以给测试起个中文名字,方便看报告时一眼就知道测的是什么。
16.1.2 配置 TestNG
如果你团队里有人喜欢TestNG,也没问题。Gradle同样支持:
dependencies {
testImplementation 'org.testng:testng:7.8.0'
}
test {
useTestNG()
}
TestNG有个好处是支持@DataProvider,可以很方便地做参数化测试。我在项目中遇到过需要测试大量边界值的情况,用DataProvider简直不要太爽。
16.2 集成测试配置
单元测试只能测单个类,但真实场景里类之间是要协作的。这时候就需要集成测试了。
Gradle里怎么做?我建议用SourceSet来隔离集成测试和单元测试:
sourceSets {
integrationTest {
java {
srcDir 'src/integrationTest/java'
}
resources {
srcDir 'src/integrationTest/resources'
}
compileClasspath += sourceSets.main.output + configurations.testRuntimeClasspath
runtimeClasspath += output + compileClasspath
}
}
task integrationTest(type: Test) {
description = '运行集成测试'
group = 'verification'
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
shouldRunAfter test
}
check.dependsOn integrationTest
你想想看,这样配置之后,./gradlew check就会先跑单元测试,再跑集成测试。如果单元测试挂了,集成测试根本不会执行——省时间。
16.3 测试报告生成
测试跑完了,怎么给别人看结果?Gradle默认会生成HTML报告,但很多人不知道它还能生成XML格式,方便CI系统解析。
16.3.1 HTML报告
默认情况下,Gradle会在build/reports/tests/test/index.html生成一份漂亮的HTML报告。里面包含了:
- 测试总数、通过数、失败数
- 每个测试类的详细结果
- 失败测试的堆栈信息
- 测试耗时统计
你什么都不用配置,直接./gradlew test,然后打开那个HTML文件就能看到。我经常在本地开发时用这个来快速定位失败的测试。
16.3.2 XML报告
CI系统(比如Jenkins、GitLab CI)更喜欢XML格式。Gradle默认也会生成XML报告,位置在build/test-results/test/*.xml。
如果你想自定义报告格式,可以这样配置:
test {
reports {
html.required = true
xml.required = true
}
}
说白了,HTML给人看,XML给机器看。两个都开着,没坏处。
16.4 知识体系图
下面这张图帮你理清测试与报告的整体结构:
16.5 实战小贴士
最后分享几个我在项目中踩过的坑:
- 测试命名规范: 我习惯用
*Test.java命名单元测试,*IT.java命名集成测试。这样Gradle可以自动识别。 - 并行执行: 如果测试之间没有依赖,可以设置
maxParallelForks = 4来加速。但要注意数据库测试可能会冲突。 - 失败重试: 有些测试不稳定(比如网络相关的),可以用
retry插件自动重试。但别滥用,不稳定测试本身就该修。
@AfterAll方法统一清理资源,问题就解决了。
好了,这一章的内容就这些。测试这东西,投入越多,回报越大。别等到线上出bug了才后悔没写测试。