我们应该如何测试将其输出写入文件的类?
我们应该将这些文件存储在哪里才能使它们在任何操作系统上运行?
我们如何确定该文件不存在?
处理文件时,如果我们尝试自己解决这些问题,编写测试可能会很困难,如下例所示。下面的测试是一个质量可疑的旧测试。它应该测试是否DogToCsvWriter序列化并将狗写入 CSV 文件:
类 DogToCsvWriterShould {
私有DogToCsvWriter writer = new DogToCsvWriter("/tmp/dogs.csv");
@测试
void convertToCsv() {
writer.appendAsCsv(新狗(品种.CORGI,颜色.BROWN,“Monty”));
writer.appendAsCsv(新狗(品种.MALTESE,颜色.WHITE,“Zoe”));
字符串 csv = Files.readString("/tmp/dogs.csv");
assertThat(csv).isEqualTo("Monty,corgi,brownnZoe,maltese,white");
}
}
序列化过程应该与写入过程分离,但让我们专注于修复测试。
上述测试的第一个问题是它在 Windows 上无法运行,因为 Windows 用户无法解析路径/tmp/dogs.csv。另一个问题是,如果文件已经存在,它将无法运行,因为上述测试执行时不会删除该文件。它可能在 CI/CD 管道中正常工作,但如果多次运行,则无法在本地运行。
JUnit 5 有一个注释,您可以使用它来获取对框架为您创建和删除的临时目录的引用。虽然创建和删除临时文件的机制因框架而异,但思路是一样的。
类 DogToCsvWriterShould {
@测试
void convertToCsv(@TempDir Path tempDir) {
路径dogsCsv = tempDir.resolve("dogs.csv");
DogToCsvWriter 作者 = 新的 DogToCsvWriter(dogsCsv);
writer.appendAsCsv(新狗(品种.CORGI,颜色.BROWN,“Monty”));
writer.appendAsCsv(新狗(品种.MALTESE,颜色.WHITE,“Zoe”));
字符串 csv = Files.readString(dogsCsv);
assertThat(csv).isEqualTo("Monty,corgi,brownnZoe,maltese,white");
}
}
通过这一小改动,我们现在可以确保上述 罗马尼亚电话号码库 测试可以在 Windows、macOS 和 Linux 上运行,而无需担心绝对路径。它还将在测试后删除创建的文件,因此我们现在可以多次运行它,并且每次都能获得可预测的结果。
命令与查询测试
命令和查询之间有什么区别?
命令:我们指示一个对象执行一个产生效果但不返回值的操作(void 方法)
查询:我们要求对象执行操作并返回结果或异常
到目前为止,我们主要测试了调用方法的查询,这些方法在执行阶段返回值或引发了异常。我们如何测试void方法并查看它们是否与其他类正确交互?框架提供了一组不同的方法来编写这些类型的测试。
到目前为止,我们为查询编写的断言都是以 开头的assertThat。在编写命令测试时,我们使用一组不同的方法,因为我们不再像查询那样检查方法的直接结果。我们希望“验证”我们的方法与系统其他部分的交互。
@ExtendWith(MockitoExtension.class)
类 FeedMentionServiceShould {
@嘲笑
私人 FeedRepository 存储库;
@嘲笑
私人 FeedMentionEventEmitter 发射器;
私人FeedMentionService服务;
@BeforeEach
无效设置(){
服务=新的FeedMentionService(存储库,发射器);
}
@测试
无效插入提及到Feed(){
长 feedId = 1L;
提及 mention = ...;
何时(repository.upsertMention(feedId,提及))
.thenReturn(UpsertResult.success(feedId,提及));
FeedInsertionEvent 事件 = 新 FeedInsertionEvent(feedId,提及);
mentionService.insertMentionToFeed(事件);
验证(发射器)。mentionInsertedToFeed(feedId,提及);
验证无更多交互(发射器);
}
}
在这个测试中,我们首先模拟我们的存储库,UpsertResult.success当被要求在我们的提要中更新插入提及时,FeedRepositoryShould它会做出响应。我们并不关心在这里测试存储库。存储库方法应该在中进行测试。通过模拟这种行为,我们实际上并没有调用存储库方法。我们只是告诉它下次调用时如何响应。
然后我们告诉我们mentionService将此提及插入到我们的 feed 中。我们知道,只有成功将提及插入到 feed 中时,它才应该发出结果。通过使用该verify方法,我们可以确保该方法mentionInsertedToFeed使用我们的提及和 feed 调用,并且不会使用再次调用verifyNoMoreInteractions。