知識庫 / Spring / Spring MVC RSS 訂閱

使用 Spring MockMvc 測試異常

Spring MVC,Testing
HongKong
5
12:53 PM · Dec 06 ,2025

1. 概述

在本文中,我們將探討在控制器中如何拋出異常,以及如何使用 Spring MockMvc 測試這些異常。

2. 從控制器中拋出異常

讓我們開始學習如何從控制器中啓動異常

我們可以將控制器中暴露的服務視為普通的 Java 函數:

@GetMapping("/exception/throw")
public void getException() throws Exception {
    throw new Exception("error");
}

現在,讓我們看看當我們調用這個服務時會發生什麼。首先,我們會注意到該服務的響應代碼是 500,這意味着內部服務器錯誤。

其次,我們收到如下的響應體:

{
    "timestamp": 1592074599854,
    "status": 500,
    "error": "Internal Server Error",
    "message": "No message available",
    "trace": "java.lang.Exception
              at com.baeldung.controllers.ExceptionController.getException(ExceptionController.java:26)
              ..."
}

綜上所述,當我們在 RestController 中拋出異常時,服務響應會自動映射為 500 響應代碼,並且異常的堆棧跟蹤包含在響應體中。

3. 異常映射到 HTTP 響應代碼

現在我們將學習如何將我們的異常映射到除了 500 之外的其他 HTTP 響應代碼。

為了實現這一點,我們將創建自定義異常並使用 Spring 提供的 <em>ResponseStatus</em> 註解。 讓我們創建這些自定義異常:

@ResponseStatus(HttpStatus.BAD_REQUEST)
public class BadArgumentsException extends RuntimeException {

    public BadArgumentsException(String message) {
        super(message);
    }
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class InternalException extends RuntimeException {

    public InternalException(String message) {
        super(message);
    }
}
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {

    public ResourceNotFoundException(String message) {
        super(message);
    }
}

第二步和最後一步是創建一個簡單的服務,在我們的控制器中拋出這些異常:

@GetMapping("/exception/{exception_id}")
public void getSpecificException(@PathVariable("exception_id") String pException) {
    if("not_found".equals(pException)) {
        throw new ResourceNotFoundException("resource not found");
    }
    else if("bad_arguments".equals(pException)) {
        throw new BadArgumentsException("bad arguments");
    }
    else {
        throw new InternalException("internal error");
    }
}

現在,讓我們來看一下為我們映射的不同異常而服務返回的不同響應:

  • 對於 not_found 異常,我們收到 404 的響應代碼
  • 給定值 bad_arguments,我們收到 400 的響應代碼
  • 對於任何其他值,我們仍然收到 500 作為響應代碼

除了響應代碼之外,我們還會收到與上一部分中收到的響應正文中相同的格式的正文。

4. 測試我們的控制器

最後,我們將看到如何測試我們的控制器是否拋出正確的異常

第一步是創建測試類並創建 MockMvc 的實例:

@Autowired
private MockMvc mvc;

接下來,讓我們為服務可以接收的每個值創建測試用例:

@Test
public void givenNotFound_whenGetSpecificException_thenNotFoundCode() throws Exception {
    String exceptionParam = "not_found";

    mvc.perform(get("/exception/{exception_id}", exceptionParam)
      .contentType(MediaType.APPLICATION_JSON))
      .andExpect(status().isNotFound())
      .andExpect(result -> assertTrue(result.getResolvedException() instanceof ResourceNotFoundException))
      .andExpect(result -> assertEquals("resource not found", result.getResolvedException().getMessage()));
}

@Test
public void givenBadArguments_whenGetSpecificException_thenBadRequest() throws Exception {
    String exceptionParam = "bad_arguments";

    mvc.perform(get("/exception/{exception_id}", exceptionParam)
      .contentType(MediaType.APPLICATION_JSON))
      .andExpect(status().isBadRequest())
      .andExpect(result -> assertTrue(result.getResolvedException() instanceof BadArgumentsException))
      .andExpect(result -> assertEquals("bad arguments", result.getResolvedException().getMessage()));
}

@Test
public void givenOther_whenGetSpecificException_thenInternalServerError() throws Exception {
    String exceptionParam = "dummy";

    mvc.perform(get("/exception/{exception_id}", exceptionParam)
      .contentType(MediaType.APPLICATION_JSON))
      .andExpect(status().isInternalServerError())
      .andExpect(result -> assertTrue(result.getResolvedException() instanceof InternalException))
      .andExpect(result -> assertEquals("internal error", result.getResolvedException().getMessage()));
}

通過這些測試,我們正在驗證響應代碼、引發的異常類型以及這些異常的消息是否與每個值相對應。

5. 結論

在本教程中,我們學習瞭如何在我們的 Spring RestController 中處理異常,以及如何測試每個暴露的服務是否拋出預期的異常。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.