【问题标题】:Testing thrown exception in controller在控制器中测试抛出的异常
【发布时间】:2015-04-01 08:45:52
【问题描述】:

我想对抛出异常的控制器方法进行测试。方法是这样的:

@RequestMapping("/do")
public ResponseEntity doIt(@RequestBody Request request) throws Exception {
    throw new NullPointerException();
}

当我尝试使用以下代码部分测试此方法时,

 mockMvc.perform(post("/do")
                .contentType(MediaType.APPLICATION_JSON)
                .content(JSON.toJson(request)))

NestedServletException 从 Spring 库中抛出。如何测试抛出 NullPointerException 而不是 NestedServletException

【问题讨论】:

  • 您正在执行 POST 并且控制器方法匹配 GET。当您将其更改为 GET 时,您将获得 NPE。
  • @NikolaB 空方法表示所有HTTP方法都映射到doItdocs.spring.io/spring/docs/current/spring-framework-reference/…
  • 我的错误尝试捕获 NestedServletException 并调用 getRootCause() 方法并查看返回的内容。
  • 原始异常由getRootCause()返回。但是不知道是不是有一些配置Spring抛出了原来的异常。
  • 不太清楚你的意思,但尝试使用 @ExceptionHandler(NullPointerException.class) 注释和参数 NullPointerException npe 以及在方法体中添加 void 方法到控制器 throw npe。

标签: java unit-testing spring-mvc


【解决方案1】:

我们的解决方案是一种变通方法:异常在通知中被捕获,错误正文作为 HTTP 响应返回。以下是模拟的工作原理:

MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller)
                        .setHandlerExceptionResolvers(withExceptionControllerAdvice())
                        .build();

private ExceptionHandlerExceptionResolver withExceptionControllerAdvice() {
    final ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
        @Override
        protected ServletInvocableHandlerMethod getExceptionHandlerMethod(final HandlerMethod handlerMethod, final Exception exception) {
            Method method = new ExceptionHandlerMethodResolver(TestAdvice.class).resolveMethod(exception);
            if (method != null) {
                return new ServletInvocableHandlerMethod(new TestAdvice(), method);
            }
            return super.getExceptionHandlerMethod(handlerMethod, exception);
        }
    };
    exceptionResolver.afterPropertiesSet();
    return exceptionResolver;
}

建议类:

@ControllerAdvice
public class TestAdvice {
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Object exceptionHandler(Exception e) {
        return new HttpEntity<>(e.getMessage());
    }
}

之后,以下测试方法成功通过:

@Test
public void testException
    mockMvc.perform(post("/exception/path"))
        .andExpect(status().is5xxServerError())
        .andExpect(content().string("Exception body"));
}

【讨论】:

  • MockMvcBuilders.standaloneSetup(controller) 行中的控制器是什么?
  • 正在测试的控制器bean,它被注入到测试类中。
【解决方案2】:

更简单的方法是将@ExceptionHandler 注入到您的Spring 测试上下文中,或者它在MockMvc.perform() 中就在.andExpect() 之前抛出异常。

@ContextConfiguration(classes = { My_ExceptionHandler_AreHere.class })
@AutoConfigureMockMvc
public class Test {
    @Autowired
    private MockMvc mvc;

    @Test
    public void test() {
        RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/update")
                .param("branchId", "13000")
                .param("triggerId", "1");
        MvcResult mvcResult = mvc.perform(requestBuilder)
                .andExpect(MockMvcResultMatchers.status().is4xxClientError())
                .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(__ -> Assert.assertThat(
                        __.getResolvedException(),
                        CoreMatchers.instanceOf(SecurityException.class)))
                .andReturn();
}

这样MvcResult.getResolvedException() 持有@Controller 的异常!

https://stackoverflow.com/a/61016827/173149

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-22
    • 2023-02-06
    • 2019-03-16
    • 1970-01-01
    • 2023-01-25
    • 1970-01-01
    • 2020-08-18
    相关资源
    最近更新 更多