我正在开发一个Spring REST应用程序,并且有一个服务来访问数据库(使用存储库)并恢复N个最后文档(I&#39 ; m使用MongoDB)。
所以,我的服务有这个功能:
@Async
public CompletableFuture<List<MessageLogViewDto>> listLogs(int total) {
// Request the entities using PageRequest to list only last N registers ordered by DATE (DESC). I don't known a better way to do this!
PageRequest page = new PageRequest(0, total, Sort.Direction.DESC, "Date");
Page<MessageLog> messages = logRepo.findAll(page);
// Convert the Entity to DTO
List<MessageLogViewDto> messageList = messages.getContent().stream().map(
message -> convertDto.toMessageLogView(message)).collect(Collectors.toList());
return CompletableFuture.completedFuture(messageList);
}
(convertDto是一个将实体转换为Dto的类)。
好的,如何对此进行单元测试? 我在几个博客上看到单元测试不应该连接到数据库。 如果我使用真正的测试数据库,这个单元测试可以变得非常简单,但我想知道在没有数据库的情况下进行此测试的更好方法(如果可能的话)。
我可以模拟存储库和函数findAll
,但如果我模拟findAll方法,我也必须模拟返回值。我不知道如何模拟Page<Object>
响应,因为Page
是一个接口,我将不得不在模拟中实现所有方法。
对于我的测试,我正在考虑使用不同的日期创建3个随机message
实体,并检查是否只返回了最后一条消息。
类似的东西:
@Test
public void shouldReturnLastMessage() {
int total = 1;
// mock findAll
// mock first entity
// mock a second entity
// mock a third entity
// ??? = must return a Page<MessageLog> with 3 entitys, how?
when(dbLogRepoMock.findAll(any(PageRequest.class))).thenReturn(???);
// call the service
List<MessageLogViewDto> result = logService.listLogs(total).join();
// check returned value
assertThat(result.size()).isEqualTo(total);
assertThat(result.get(0).getMensagem()).isEqualTo("third message"); // last message
// check if repository was called
verify(dbLogRepoMock).findAll(any(PageRequest.class));
}
任何帮助?
答案 0 :(得分:1)
这可能是一个有点引起争议的观点,但我会专注于单元测试仅您的转换器,因为此方法中没有其他有意义的自定义逻辑。
看看它的方法:
// 1 - Create an instance of a Spring class
PageRequest page = new PageRequest(0, total, Sort.Direction.DESC, "Date");
// 2 - Query a Spring Repository with the Spring Class
Page<MessageLog> messages = logRepo.findAll(page);
// 3 - CUSTOM LOGIC to convert result to custom DTO class
List<MessageLogViewDto> messageList = messages.getContent().stream().map(
message -> convertDto.toMessageLogView(message)).collect(Collectors.toList());
// 4 - Return a Java standard CompleteableFuture
return CompletableFuture.completedFuture(messageList);
即使您要为此方法编写单元测试,
1是简单的类实例化 2使用1的结果 - 但你无论如何都要创建一个模拟响应,所以它不会有意义地运用1。 3是您的转换器逻辑,您可以直接编写独立测试 4正在利用核心java功能,你不太可能发现
的错误此外,请查看方法的签名:
public CompletableFuture<List<MessageLogViewDto>> listLogs(int total) {
它接受一个整数total
并返回CompleteableFuture
(我们不关心测试的实现,因为它不是此方法的核心功能/是内置的),包含一个元素列表。假设是一个大小为total
的列表。
如果没有实际访问数据库,则必须将返回的数据模拟为预期大小。确定结果大小的实际逻辑是数据访问框架的一部分,因此您甚至无法验证输出数据大小是否与方法的输入参数实际匹配。在我的估计中没有多少价值。
我通常不专注于单元测试数据访问方法,这些方法只是在没有任何有意义的逻辑的情况下访问和返回数据。在这种情况下,只有有意义的逻辑出现在您的转换器中,因此我将专注于测试。
您可以提取类似的方法:
List<MessageLogViewDTO> convertMessageLogsToMessageLogViewDTO(List<MessageLog> messages) {
return messages.getContent().stream().map(
message -> convertDto.toMessageLogView(message)).collect(Collectors.toList());
}
然后你可以简单地用各种情况测试该方法(有效数据,空/空列表等等。