0

I have an error controller (to handle the path "/error") that works when the application is running, but when in an unit test with @WebMvcTest it does not work.

The error controller also works if I send a request direct to its path.

This is my error controller:

@Controller
public class ErrorController implements org.springframework.boot.web.servlet.error.ErrorController {

    @RequestMapping("/error")
    public ResponseEntity<List<Error>> handleError(HttpServletRequest request) {

and this is my test class:

@RunWith(SpringRunner.class)
@WebMvcTest({ErrorController.class})
public class ErrorControllerTest {

    @Autowired
    private MockMvc mockMvc;

I have also tried to add the class ErrorMvcAutoConfiguration in the WebMvcTest annotation.

I have debugged the ErrorMvcAutoConfiguration class and found that when the application is running it finds an error view resolver, but when running as unit test it does not find any.

The idea behind this test it to make sure the Spring configuration (which is code) that leads to the execution of this error controller is correct.

  • I have further debugged the application and found that Tomcat is responsible for forwarding to the error page when status 404 is returned by the servlet. – Constantino Cronemberger Dec 24 '18 at 10:53
  • Found another way to handle this case: configure Spring to throw an exception if it can't handle the requested path and then handle the exception in a regular exception handler. https://stackoverflow.com/questions/28902374/spring-boot-rest-service-exception-handling/30193013#30193013 – Constantino Cronemberger Dec 24 '18 at 11:22

1 Answers1

0

You are not performing a unit test if you expect to trigger the ErrorController by calling a method in MyController. That is an integration test and you don't need to do it.

If you describe your test as this: "I want to see that an exception from the MyController class lands in the ErrorController class" then you are not testing either the MyController class or the ErrorController class; instead, you are testing that Spring works. You don't need to test that Spring works. The authors of Spring test to see that Spring works.

Iff you want to test that the annotation in the ErrorController is correct such that Spring defines it as you ErrorController class as the error controller, then you are on the correct path. That is still an integration test and not a unit test.

To unit test the ErrorController class, just create an instance of the ErrorController class in a unit test and call the methods. You can use reflection in the unit test to verify that the annotations "appear correct to you". Here is a simple example ErrorController unit test.

public TestErrorController
{
  private ErrorController classToTest;

  @Mock
  private HttpServletRequest mockHttpServletRequest;

  private
  @Before
  public void beforeTest()
  {
    MockitoAnnotations.initMocks(this);

    classToTest = new ErrorController();
  }

  @Test
  public void handleError_allGood_success()
  {
    private ResponseEntity<List<Error>> actualResult;

    // mock the desired mockHttpServletRequest functionality.
    doReturn(something).when(mockHttpServletRequest).someMethod();


    // Perform the test.
    actualResult = classToTest.handleError(mockHttpServletRequest);


    // Do asserts on the actualResult here.
  }
}
DwB
  • 37,124
  • 11
  • 56
  • 82
  • Thanks for your answer. I have reworked part of the question, so I have removed the other controller and added information about the intention of the test. I think this should be possible because using @@ExceptionHandler and @@ControllerAdvice I can create tests that verify that my controllers are giving error 404 when they are passed wrong ids (in this case I am testing that the exception handler is well configured). Now I want to test that when the path is not handled by any other controllers it will give 404 with the right format. – Constantino Cronemberger Dec 23 '18 at 10:47