【问题标题】:Testing @RestController with @ControllerAdvice使用 @ControllerAdvice 测试 @RestController
【发布时间】:2014-09-06 01:30:25
【问题描述】:

我的问题与测试 Spring @RestController 有关,它也将 @ControllerAdvice 与 @ExceptionHandler 一起使用。代码如下:

@ControllerAdvice 类:

@ControllerAdvice
public class MyAppExceptionHandler {

    @ExceptionHandler({ NoSuchEntityException.class })
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    public @ResponseBody
    ErrorDTO handleNotFoundException(Exception ex) throws IOException {

        return new ErrorDTO.Builder().setStatus(HttpStatus.NOT_FOUND)
                .setCause(ex.getClass().getName())
                .setThrowable(ex).build();
    }
}

在应用程序中使用它时一切正常 - 完美地获得带有 JSON 解释的 404 响应,但在测试期间尝试使用它时 - 会发生不好的事情。

我的测试班:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { WebConfig.class })
@WebAppConfiguration
public class SomeTest {

    @Mock
    private SomeService service;

    @InjectMocks
    private SomeController controller;

    private MockMvc mvc;

    private ExceptionHandlerExceptionResolver createExceptionResolver() {
        ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
            @Override
            protected ServletInvocableHandlerMethod getExceptionHandlerMethod(
                HandlerMethod handlerMethod, Exception exception) {
                Method method = new ExceptionHandlerMethodResolver(
                        MyAppExceptionHandler.class).resolveMethod(exception);
                return new ServletInvocableHandlerMethod(
                    new MyAppExceptionHandler(), method);
            }
        };
        exceptionResolver.afterPropertiesSet();
        return exceptionResolver;
    }

    @Before
    public void setup() {

        MockitoAnnotations.initMocks(this);
        mvc = MockMvcBuilders.standaloneSetup(controller)
                .setHandlerExceptionResolvers(createExceptionResolver())
                .build();
    }

    @Test
    public void thatExceptionHappens() throws Exception {

        when(service.get(10)).thenThrow(new NoSuchEntityException(Some.class, 10));

        mvc.perform(get("/api/some/10")).andExpect(status().isNotFound());
    }
}

尝试运行时:

2014-07-15 19:35:01.376 [main] ERROR com.package.SomeTest$1 - Failed to invoke @ExceptionHandler method: public com.package.ErrorDTO com.package.MyAppExceptionHandler.handleNotFoundException(java.lang.Exception) throws java.io.IOException
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

我认为在测试我的@ExceptionHandler 期间可能没有加载 MappingJackson2HttpMessageConverter(但是它是在 WebConfig.class 中配置的,并且在尝试执行典型测试时 - 没有抛出任何异常 - 一切正常)。

提前感谢您的帮助。

【问题讨论】:

  • 你的 WebConfig 的内容是什么?
  • 您提出了一个问题,人们已经花时间回答了。请接受答案。

标签: java spring junit


【解决方案1】:

MockMvcBuilders StandaloneSetup 根据定义是手动的,这意味着它不会像在 Spring 配置中发现像 @ControllerAdvice 这样感兴趣的 Spring bean,它允许您手动设置测试所需的内容。相反,standaloneSetup 应该允许您手动注册 @ControllerAdvice bean。有一张票可以做到这一点。见https://jira.spring.io/browse/SPR-12751

【讨论】:

  • 感谢@Rossen 实现这一点。 Spring 4.2 附带了这个改进,Spring Boot 1.3.0 也有这个,因为它依赖于 Spring 4.2+。
【解决方案2】:

我不确定这是否是最好的解决方案(我想听听另一个人的意见),
但这就是我解决您面临的这个问题的方法:

将此行添加到您的createExceptionResolver():

exceptionResolver.getMessageConverters().add(
        new MappingJackson2HttpMessageConverter());

类似这样的:

private ExceptionHandlerExceptionResolver createExceptionResolver() {
    ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {
        @Override
        protected ServletInvocableHandlerMethod getExceptionHandlerMethod(
            HandlerMethod handlerMethod, Exception exception) {
            Method method = new ExceptionHandlerMethodResolver(
                    MyAppExceptionHandler.class).resolveMethod(exception);
            return new ServletInvocableHandlerMethod(
                new MyAppExceptionHandler(), method);
        }
    };
    exceptionResolver.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    exceptionResolver.afterPropertiesSet();
    return exceptionResolver;
}

出于某种我不知道的原因,Spring 没有加载我的 MappingJackson2HttpMessageConverter
那条线解决了我的问题。

【讨论】:

  • 请注意,当您在构建器中设置HandlerExceptionResolvers 时,您将清除所有默认值并使用您的替代它们的。如果您有任何使用验证注释的测试并期望来自 Spring 的适当响应,这可能会导致您出现问题。我在 Spring 上提出了一个问题,要求他们允许我们添加一个解析器而不是覆盖:jira.spring.io/browse/SPR-12751
  • 今天花了 3 个小时,直到我像你一样用 exceptionResolver.getMessageConverters().add(...) 解决了问题。这是病态!默认情况下,在 ExceptionHandlerExceptionResolver 构造函数中只添加了 4 个转换器,而 Jackson 不存在。
猜你喜欢
  • 2019-10-03
  • 1970-01-01
  • 2020-08-02
  • 2023-03-10
  • 1970-01-01
  • 1970-01-01
  • 2018-04-21
  • 2021-11-22
  • 1970-01-01
相关资源
最近更新 更多