Testing Spring MVC @ExceptionHandler method with Spring MVC Test

前端 未结 7 1819
悲&欢浪女
悲&欢浪女 2020-12-04 20:56

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

@ControllerAdvice
public class ExceptionController {

    @ExceptionHandler(Throwa         


        
相关标签:
7条回答
  • 2020-12-04 21:28

    This is better:

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

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

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

    ...tested on Spring 4.0.2.RELEASE

    0 讨论(0)
  • 2020-12-04 21:28

    I had the same issue; This worked for me:

    *RuntimeException in thenThrow(); ErrorHandler won't catch Exception or Throwable parent classes.
    *Remove all try-catch sentences of methods being tested
    *No @Before or @ComponentScan annotations were needed at all

    when(getRejectionQuery.execute(anyInt(), anyInt(), anyMap())).thenThrow(new RuntimeException());
    
    0 讨论(0)
  • 2020-12-04 21:29

    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();
    }
    
    0 讨论(0)
  • 2020-12-04 21:34

    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.

    You can configure this setup with the following approach:

    Given a custom RecordNotFound exception...

    @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

    @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.

     @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().

        @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 MappingJackson2HttpMessageConverter());
        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.

    0 讨论(0)
  • 2020-12-04 21:39

    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

    Hoping my answer help you out

    0 讨论(0)
  • 2020-12-04 21:49

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

    @Before
    public void setup() {
        this.mockMvc = standaloneSetup(commandsController)
            .setHandlerExceptionResolvers(withExceptionControllerAdvice())
            .setMessageConverters(new MappingJackson2HttpMessageConverter()).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;
    }
    
    0 讨论(0)
提交回复
热议问题