Testing Exception-Handling in Spring-MVC

Specifying Exception-Handlers for Controllers in Spring MVC

Spring offers the annotation @ExceptionHandler to handle exceptions thrown by controllers. The annotation can be added to methods of a specific controller, or to methods of a @Component-class, that is itself annotated with @ControllerAdvice. The latter defines global exception-handling, that will be carried out by the DispaterServlet for all controllers. The former specifies exception-handlers for a single controller-class.

This mechanism is documented in the Springframework Documentation and it is neatly summarized in the blog-article Exception Handling in Spring MVC. In this article, we will focus on testing the sepcified exception-handlers.

Testing Exception-Handlers with the @WebMvcTest-Slice

Spring-Boot offers the annotation @WebMvcTest for tests of the controller-layer of your application. For a test annotated with @WebMvcTest, Spring-Boot will:

  • Auto-configure Spring MVC, Jackson, Gson, Message converters etc.
  • Load relevant components (@Controller, @RestController, @JsonComponent etc.)
  • Configure MockMVC

All other beans configured in the app will be ignored. Hence, a @WebMvcTest fits perfectly for testing exception-handlers, which are part of the controller-layer. It enables us, to mock away the other layers of the application and concentrate on the part, that we want to test.

Consider the following controller, that defines a request-handling and an accompanying exception-handler, for an IllegalArgumentException, that may by thrown in the business-logic:

public class ExampleController
  ExampleService service;

  public String controller(
      @RequestParam(required = false) Integer answer,
      Model model)
    Boolean outcome = answer == null ? null : service.checkAnswer(answer);
    model.addAttribute("answer", answer);
    model.addAttribute("outcome", outcome);
   return "view";

  public ModelAndView illegalArgumentException(IllegalArgumentException e)
    LOG.error("{}: {}", HttpStatus.BAD_REQUEST, e.getMessage());
    ModelAndView mav = new ModelAndView("400");
    mav.addObject("exception", e);
    return mav;

The exception-handler resolves the exception as 400: Bad Request and renders the specialized error-view 400.

With the help of @WebMvcTest, we can easily mock away the actual implementation of the business-logic and concentrate on the code under test: our specialized exception-handler.

class ExceptionHandlingApplicationTests
  @MockBean  ExampleService service;
  @Autowired MockMvc mvc;

  void test400ForExceptionInBusinessLogic() throws Exception {
    when(service.checkAnswer(anyInt())).thenThrow(new IllegalArgumentException("FOO!"));


    verify(service, times(1)).checkAnswer(anyInt());

We preform a GET with the help of the provided MockMvc and check, that the status of the response fullfills our expectations, if we tell our mocked business-logic to throw the IllegalArgumentException, that is resolved by our exception-handler.

Leave a Reply

Your email address will not be published. Required fields are marked *