1

我有一個Spring Boot應用程序,並希望通過集成測試來覆蓋我的REST控制器。 這裏是我的控制器:Spring Boot Testing:REST控制器中的異常

@RestController 
@RequestMapping("/tools/port-scan") 
public class PortScanController { 
    private final PortScanService service; 

    public PortScanController(final PortScanService portScanService) { 
     service = portScanService; 
    } 

    @GetMapping("") 
    public final PortScanInfo getInfo(
      @RequestParam("address") final String address, 
      @RequestParam(name = "port") final int port) 
      throws InetAddressException, IOException { 
     return service.scanPort(address, port); 
    } 
} 

在測試情況下,我想測試端點的一個動作在某些情況下例外。這裏是我的測試類:

@RunWith(SpringRunner.class) 
@WebMvcTest(PortScanController.class) 
public class PortScanControllerIT { 
    @Autowired 
    private MockMvc mvc; 

    private static final String PORT_SCAN_URL = "/tools/port-scan"; 

    @Test 
    public void testLocalAddress() throws Exception { 
     mvc.perform(get(PORT_SCAN_URL).param("address", "192.168.1.100").param("port", "53")).andExpect(status().isInternalServerError()); 
    } 
} 

這樣做的最佳方法是什麼?當前實現不處理InetAddressException這是從PortScanController.getInfo拋出(),當我開始測試,我接受和錯誤:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.handytools.webapi.exceptions.InetAddressException: Site local IP is not supported 

這是不可能的指定@Test註解預期異常,因爲原來InetAddressException是用NestedServletException包裝。

回答

2

你可以定義一個異常處理程序

@ExceptionHandler(InetAddressException.class) 
@ResponseStatus(HttpStatus.BAD_REQUEST) 
@ResponseBody 
public Response handledInvalidAddressException(InetAddressException e) 
{ 
    log e 
    return getValidationErrorResponse(e); 
} 

,然後在您的測試,你可以做

mvc.perform(get(PORT_SCAN_URL) 
    .param("address", "192.168.1.100") 
    .param("port", "53")) 
    .andExpect(status().isBadRequest()) 
    .andExpect(jsonPath("$.response").exists()) 
    .andExpect(jsonPath("$.response.code", is(400))) 
    .andExpect(jsonPath("$.response.errors[0].message", is("Site local IP is not supported"))); 
+0

謝謝,鮑里斯。考慮到我有自動配置的MockMvc實例,我該怎麼做? – DavyJohnes

+0

我的意思是你的應用程序的異常處理程序,而不是你的測試。因此,您的應用程序聲明'@ExceptionHandler(InetAddressException.class)',然後用一個描述錯誤的消息以400或503狀態碼進行響應,然後您的測試將查找預期的狀態碼和預期的錯誤消息作爲響應。 – borowis

+0

,因爲你得到的確實是一個驗證錯誤,因此一個400代碼和一個錯誤消息似乎對我來說似乎是合適的 – borowis

4

爲了檢驗包裝的異常(即InetAddressException),你可以創建一個JUnit使用ExpectedException類的規則然後設置expectMessage()(從NestedServletExceptiongetMessage()收到,其中包含實際原因),可以參考下面的代碼相同:

@Rule 
public ExpectedException inetAddressExceptionRule = ExpectedException.none(); 

@Test 
public void testLocalAddress() { 

    //Set the message exactly as returned by NestedServletException 
    inetAddressExceptionRule.expectMessage("Request processing failed; nested exception is com.handytools.webapi.exceptions.InetAddressException: Site local IP is not supported"); 

    //or you can check below for actual cause 
    inetAddressExceptionRule.expectCause(org.hamcrest.Matchers.any(InetAddressException.class)) 

    //code for throwing InetAddressException here (wrapped by Spring's NestedServletException) 
} 

你可以在這裏指的的ExpectedException API:

http://junit.org/junit4/javadoc/4.12/org/junit/rules/ExpectedException.html

+0

不幸的是,它不起作用。正如我在我的問題中提到的,原始異常是用NestedServletException包裝的。 – DavyJohnes

+0

已經完成了。它不起作用。 jUnit不處理這個異常。 – DavyJohnes

+0

看看我的代碼創建ExpectedException規則 – developer

6

春天開機測試包帶有AssertJ有驗證拋出的異常的非常方便的方式。

驗證原因:

@Test 
public void shouldThrowException() { 
    assertThatThrownBy(() -> methodThrowingException()).hasCause(InetAddressException .class); 
} 

也有幾個方法,你可能會感興趣,我建議具有docs看看。