使用 Spring MVC 测试测试 Spring MVC @ExceptionHandler 方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16669356/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 05:59:29  来源:igfitidea点击:

Testing Spring MVC @ExceptionHandler method with Spring MVC Test

springspring-mvcmockitospring-mvc-test

提问by C0deAttack

I have the following simple controller to catch any unexpected exceptions:

我有以下简单的控制器来捕获任何意外的异常:

@ControllerAdvice
public class ExceptionController {

    @ExceptionHandler(Throwable.class)
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public ResponseEntity handleException(Throwable ex) {
        return ResponseEntityFactory.internalServerErrorResponse("Unexpected error has occurred.", ex);
    }
}

I'm trying to write an integration test using Spring MVC Test framework. This is what I have so far:

我正在尝试使用 Spring MVC 测试框架编写集成测试。这是我到目前为止:

@RunWith(MockitoJUnitRunner.class)
public class ExceptionControllerTest {
    private MockMvc mockMvc;

    @Mock
    private StatusController statusController;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(new ExceptionController(), statusController).build();
    }

    @Test
    public void checkUnexpectedExceptionsAreCaughtAndStatusCode500IsReturnedInResponse() throws Exception {

        when(statusController.checkHealth()).thenThrow(new RuntimeException("Unexpected Exception"));

        mockMvc.perform(get("/api/status"))
                .andDo(print())
                .andExpect(status().isInternalServerError())
                .andExpect(jsonPath("$.error").value("Unexpected Exception"));
    }
}

I register the ExceptionController and a mock StatusController in the Spring MVC infrastructure. In the test method I setup an expectation to throw an exception from the StatusController.

我在 Spring MVC 基础设施中注册了 ExceptionController 和一个模拟 StatusController。在测试方法中,我设置了从 StatusController 抛出异常的期望。

The exception is being thrown, but the ExceptionController isn't dealing with it.

正在抛出异常,但 ExceptionController 没有处理它。

I want to be able to test that the ExceptionController gets exceptions and returns an appropriate response.

我希望能够测试 ExceptionController 是否获取异常并返回适当的响应。

Any thoughts on why this doesn't work and how I should do this kind of test?

关于为什么这不起作用以及我应该如何进行这种测试的任何想法?

Thanks.

谢谢。

回答by Brian Matthews

I just had the same issue and the following works for me:

我刚刚遇到了同样的问题,以下对我有用:

@Before
public void setup() {
    this.mockMvc = MockMvcBuilders.standaloneSetup(statusController)
         .setControllerAdvice(new ExceptionController())
        .build();
}

回答by Leszek Grucha?a

This code will add ability to use your exceptions controlled advice.

此代码将添加使用您的异常控制建议的能力。

@Before
public void setup() {
    this.mockMvc = standaloneSetup(commandsController)
        .setHandlerExceptionResolvers(withExceptionControllerAdvice())
        .setMessageConverters(new MappingHymanson2HttpMessageConverter()).build();
}

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

回答by Agung Setiawan

Since you are using stand alone setup test you need to provide exception handler manually.

由于您使用的是独立设置测试,因此您需要手动提供异常处理程序。

mockMvc= MockMvcBuilders.standaloneSetup(adminCategoryController).setSingleView(view)
        .setHandlerExceptionResolvers(getSimpleMappingExceptionResolver()).build();

I had same problem a few days back, you can see my problem and solution answered by myself here Spring MVC Controller Exception Test

几天前我遇到了同样的问题,您可以在Spring MVC Controller Exception Test 中看到我自己回答的问题和解决方案

Hoping my answer help you out

希望我的回答能帮到你

回答by softjake

Use Spring MockMVC to emulate a servletContainer to a point where you can incorporate any request filtering or exception handling tests in your unit tests suite.

使用 Spring MockMVC 将 servletContainer 模拟到可以在单元测试套件中合并任何请求过滤或异常处理测试的程度。

You can configure this setup with the following approach:

您可以使用以下方法配置此设置:

Given a custom RecordNotFound exception...

鉴于自定义 RecordNotFound 异常...

@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Record not found") //
public class RecordNotFoundException extends RuntimeException {

    private static final long serialVersionUID = 8857378116992711720L;

    public RecordNotFoundException() {
        super();
    }

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

... and a RecordNotFoundExceptionHandler

...和一个 RecordNotFoundExceptionHandler

@Slf4j
@ControllerAdvice
public class BusinessExceptionHandler {

    @ExceptionHandler(value = RecordNotFoundException.class)
    public ResponseEntity<String> handleRecordNotFoundException(
            RecordNotFoundException e,
            WebRequest request) {
         //Logs
        LogError logging = new LogError("RecordNotFoundException",
                HttpStatus.NOT_FOUND, 
                request.getDescription(true));
        log.info(logging.toJson());

        //Http error message
        HttpErrorResponse response = new HttpErrorResponse(logging.getStatus(), e.getMessage());
        return new ResponseEntity<>(response.toJson(),
                HeaderFactory.getErrorHeaders(),
                response.getStatus());
    }
   ...
}

Configure a tailored test context: set a @ContextConfiguration to specify the classes you need for your test. Set Mockito MockMvc as a servlet container emulator and set your tests fixture and dependencies.

配置定制的测试上下文:设置 @ContextConfiguration 以指定测试所需的类。将 Mockito MockMvc 设置为 servlet 容器模拟器并设置您的测试装置和依赖项。

 @RunWith(SpringRunner.class)
@ContextConfiguration(classes = {
    WebConfig.class,
    HeaderFactory.class,
})
@Slf4j
public class OrganisationCtrlTest {

    private MockMvc mvc;

    private Organisation coorg;

    @MockBean
    private OrganisationSvc service;

    @InjectMocks
    private OrganisationCtrl controller = new OrganisationCtrl();

    //Constructor
    public OrganisationCtrlTest() {
    }
   ....

Configure a mock MVC "servlet emulator": register handler beans in the context and build the mockMvc emulator (Note: there are two possible configuration: standaloneSetup or webAppContextSetup; refer to the documentation). The builder rightfully implements the Builder pattern so you can chain configuration commands for exception resolvers and handlers before calling build().

配置模拟 MVC“servlet 模拟器”:在上下文中注册处理程序 bean 并构建 mockMvc 模拟器(注意:有两种可能的配置:standaloneSetup 或 webAppContextSetup;请参阅文档)。构建器正确地实现了构建器模式,因此您可以在调用 build() 之前链接异常解析器和处理程序的配置命令。

    @Before
    public void setUp() {
        final StaticApplicationContext appContext = new StaticApplicationContext();
        appContext.registerBeanDefinition("BusinessExceptionHandler",
                new RootBeanDefinition(BusinessExceptionHandler.class, null, null));

//InternalExceptionHandler extends ResponseEntityExceptionHandler to //handle Spring internally throwned exception
        appContext.registerBeanDefinition("InternalExceptionHandler",
                new RootBeanDefinition(InternalExceptionHandler.class, null,
                        null));
        MockitoAnnotations.initMocks(this);
        mvc = MockMvcBuilders.standaloneSetup(controller)
                .setHandlerExceptionResolvers(getExceptionResolver(appContext))
                .build();
        coorg = OrganisationFixture.getFixture("orgID", "name", "webSiteUrl");
    }
    ....

Get the exception resolver

获取异常解析器

private ExceptionHandlerExceptionResolver getExceptionResolver(
        StaticApplicationContext context) {
    ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
    resolver.getMessageConverters().add(
            new MappingHymanson2HttpMessageConverter());
    resolver.setApplicationContext(context);
    resolver.afterPropertiesSet();
    return resolver;
}

Run your tests

运行你的测试

    @Test
    public void testGetSingleOrganisationRecordAnd404() throws Exception {
        System.out.println("testGetSingleOrganisationRecordAndSuccess");
        String request = "/orgs/{id}";
        log.info("Request URL: " + request);

        when(service.getOrganisation(anyString())).
                thenReturn(coorg);
        this.mvc.perform(get(request)
                .accept("application/json")
                .andExpect(content().contentType(
                        .APPLICATION_JSON))
                .andExpect(status().notFound())
                .andDo(print());
    }
    ....
}

Hope this helps.

希望这可以帮助。

Jake.

Hyman。

回答by Adam Dec

This is better:

这个更好:

((HandlerExceptionResolverComposite) wac.getBean("handlerExceptionResolver")).getExceptionResolvers().get(0)

And do not forget to scan for @ControllerAdvice beans in your @Configuration class:

并且不要忘记扫描 @Configuration 类中的 @ControllerAdvice bean:

@ComponentScan(basePackages = {"com.company.exception"})

...tested on Spring 4.0.2.RELEASE

...在 Spring 4.0.2.RELEASE 上测试

回答by thalespf

Try it;

尝试一下;

@RunWith(value = SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { MVCConfig.class, CoreConfig.class, 
        PopulaterConfiguration.class })
public class ExceptionControllerTest {

    private MockMvc mockMvc;

    @Mock
    private StatusController statusController;

    @Autowired
    private WebApplicationContext wac;

    @Before
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
    }

    @Test
    public void checkUnexpectedExceptionsAreCaughtAndStatusCode500IsReturnedInResponse() throws Exception {

        when(statusController.checkHealth()).thenThrow(new RuntimeException("Unexpected Exception"));

        mockMvc.perform(get("/api/status"))
                .andDo(print())
                .andExpect(status().isInternalServerError())
                .andExpect(jsonPath("$.error").value("Unexpected Exception"));
    }
}