请点赞支持这款 全新设计的脚手架 ,让 Java 再次伟大!
单元测试的设计哲学
程序首先是写给人读的,然后顺便让机器能够运行。
Programs must be written for people to read, and only incidentally for machines to execute.
而编写编程的第一步就是命名,单元测试也一样。
WWW
如何让单元测试的命名被人读懂呢?你需要在命名中体现三个要素,简称 WWW 原则。
- 你要测什么?(what)
- 在什么条件下测?(when)
- 你期待什么表现?(want)
下面来看一个 MJGA 脚手架中的单元测试示例。
@Test
void createVerifyGetSubjectJwt_givenUserIdentify_shouldReturnTrueAndGetExpectIdentify() {
String jwt = cookieJwt.createJwt("1");
assertThat(cookieJwt.verifyToken(jwt)).isTrue();
assertThat(cookieJwt.getSubject(jwt)).isEqualTo("1");
}
分三个部分拆分这个命名如下:
createVerifyGetSubjectJwt
体现了要测试的对象。givenUserIdentify
表示了测试的条件。shouldReturnTrueAndGetExpectIdentify
阐述了期待的行为。
这就是一个好的命名——一个业务人员可以读懂的命名。
AAA
第一关结束了,现在来实现测试逻辑。其实有了 WWW 的命名设计,逻辑的实现已经有据可循。和命名一样,测试逻辑也有原则可以参考,通常被称为 AAA 原则。
- 准备(Arrange)
- 执行(Act)
- 断言(Assert)
继续来看一个 MJGA 脚手架的测试案例:
@Test
@WithMockUser
void signIn_givenValidHttpRequest_shouldSucceedWith200() throws Exception {
String stubUsername = "test_04cb017e1fe6";
String stubPassword = "test_567472858b8c";
SignInDto signInDto = new SignInDto();
signInDto.setUsername(stubUsername);
signInDto.setPassword(stubPassword);
when(signService.signIn(signInDto)).thenReturn(1L);
mockMvc
.perform(
post("/auth/sign-in")
.contentType(MediaType.APPLICATION_JSON)
.content(
"""
{
"username": "test_04cb017e1fe6",
"password": "test_567472858b8c"
}
""")
.with(csrf()))
.andExpect(status().isOk());
}
Arrange
这是测试的准备阶段。在这个阶段你需要构造一些提供上下文使用的代码,比如插入数据,构建对象,乃至更复杂的 mock 与 stub 都在此列。在案例中我们构建了 SignInDto 对象供后续使用,并假设了 signIn 方法的返回值——这些都是在为后续的测试做准备。
Act
这是执行阶段,在案例中对应 mockMvc.perfom
这里只是 Api 比较复杂,你就理解成一行代码就行。
Assert
你需要清晰的表明你期待的结果是什么。在案例中对应 .andExpect(status().isOk());
很多时候可能需要写一些测试方法用来验证某个逻辑是否能够正常运行不报错,因为方法本身没有返回值。这很容易,使用 assertDoesNotThrow
来解决这个问题。
// pause & resume job
JobKey firstDataBackupJobKey = dataBackupJobKeys.iterator().next();
assertDoesNotThrow(
() -> {
dataBackupScheduler.pauseJob(firstDataBackupJobKey);
dataBackupScheduler.resumeJob(firstDataBackupJobKey);
});
结语
这些编码哲学和你用什么语言和框架无关,任何单元测试都是靠这种思维写出来的。更多的单元测试内容待我后续整理好后发出。大家喜欢的话不妨购买一个 MJGA 脚手架的 Pro 版本支持我创作更多的内容,谢谢各位佬们。