簡體   English   中英

如何對使用存儲庫的服務層進行春季單元測試?

[英]How to do a Spring Unit Test of a Service layer that use Repository?

我正在開發一個Spring REST應用程序,並且有一個服務 (使用Repository )訪問數據庫並恢復N個最后一個文檔(我正在使用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));
}

有什么幫助嗎?

這可能是一個溫和的爭議意見,但我會集中在單位,因為在這種方法沒有其他有意義的定制邏輯測試只是你的轉換器。

查看它的方法:

// 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 (我們不關心要測試的實現,因為它不是此方法的核心功能/是內置的)。 Assumedly大小的名單total

在沒有實際訪問數據庫的情況下,您將必須模擬返回的數據以達到預期大小。 確定結果大小的實際邏輯是數據訪問框架的一部分,因此,您甚至無法驗證輸出數據大小是否確實與方法的輸入參數匹配。 我的估計沒有太多價值。

我通常不關注僅在沒有任何有意義的邏輯的情況下訪問和返回數據的單元測試數據訪問方法。 在這種情況下,轉換器中只會出現有意義的邏輯,因此我將重點測試它。

您可以提取如下方法:

List<MessageLogViewDTO> convertMessageLogsToMessageLogViewDTO(List<MessageLog> messages) {
  return messages.getContent().stream().map(
    message -> convertDto.toMessageLogView(message)).collect(Collectors.toList());
}

然后您可以簡單地使用各種情況(有效數據,空/空列表等)測試該方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM