M
M
MaxLich2019-04-08 17:29:55
Java
MaxLich, 2019-04-08 17:29:55

How to test the controller along with error trapping through ControllerAdvice?

Hello. I use spring 5 along with spring boot 5, junit 5, mvc. You need to test the controller along with a class annotated with the @ControllerAdvice annotation. My class with tests:

spoiler
@WebMvcTest(controllers = ExportToMsExcelController.class, secure = false)
class ExportToMsExcelControllerTests {

    private static final String EXPORT_RESOURCE_1_URL = "/resource1/list/ms-excel"; // URL для rest-запроса по выгрузки в эксель
    private static final String CONTENT_TYPE = "application/vnd.ms-excel";

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ObjectMapper objectMapper;

    @MockBean
    private CreateXLSXDocumentService createXLSXDocumentService;

    /**
     * Тест выгрузки в файл в формате MS Excel,
     * входные данные: нет (search-строка не указана),
     * выходные данные: ошибка 500, непустой текст ошибки,
     * особенности: внутренний сервис вернул null
     *
     * @throws Exception любые исключительные ситуации
     */
    @Test
    void exportTable_noSearchStringAndInternalServiceReturnsNull_HttpCode500AndErrorMessageReturned() throws Exception {

        given(createXLSXDocumentService.createXLSXDocument(anyMap()))
                .willReturn(null);


        final MvcResult mvcResult = mockMvc.perform(
                get(EXPORT_RESOURCE_1_URL)
                        .accept(CONTENT_TYPE)
        )
                .andDo(print())
                .andExpect(status().isInternalServerError())
                .andReturn();

        final String errorMessage = mvcResult.getResponse().getErrorMessage();
        assertNotNull(errorMessage, "errorMessage is null");
        assertTrue(errorMessage.length() > 0, "errorMessage.length() <= 0");

    }

And the ControllerAdvice class:
spoiler
@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
    private final static Logger logger = LogManager.getLogger(RestExceptionHandler.class);



//реализации методов абстрактного класса

    @ExceptionHandler({ NullPointerException.class })
    public ResponseEntity<Object> handleNullPointerException(NullPointerException ex, WebRequest request) {
        logger.error(ex.getLocalizedMessage(), ex);
        return buildResponseEntity(new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage(), ex, null, new ArrayList<> (Arrays.asList(ex.getStackTrace()))));
    }
    @ExceptionHandler({ IllegalArgumentException.class })
    public ResponseEntity<Object> handleIllegalArgumentException(IllegalArgumentException ex, WebRequest request) {
        logger.error(ex.getLocalizedMessage(), ex);
        return buildResponseEntity( new ApiError(HttpStatus.BAD_REQUEST, ex.getMessage(), ex, null, new ArrayList<>(Arrays.asList(ex.getStackTrace()))) );
    }

    @ExceptionHandler({ RuntimeException.class })
    public ResponseEntity<Object> handleRuntimeException(RuntimeException ex, WebRequest request) {
        logger.error(ex.getLocalizedMessage(), ex);
        return buildResponseEntity(new ApiError(HttpStatus.INTERNAL_SERVER_ERROR, ex.getMessage(), ex, null, new ArrayList<> (Arrays.asList(ex.getStackTrace()))));
    }

    @ExceptionHandler({ javax.validation.ConstraintViolationException.class })
    public ResponseEntity<Object> handleConstraintViolationException(javax.validation.ConstraintViolationException ex, WebRequest request) {
        logger.error(ex.getMessage(), ex);
        String message = ex.getMessage();
        return buildResponseEntity(new ApiError(HttpStatus.BAD_REQUEST, message, ex, null, new ArrayList<> (Arrays.asList(ex.getStackTrace()))));
    }

    private ResponseEntity<Object> buildResponseEntity(ApiError apiError) {
        return new ResponseEntity<>(apiError, apiError.getStatus());
    }
}

The problem is that during the tests it does not go into any of the methods of the ControllerAdvice class. Although during the actual operation of the program, the corresponding methods of this class are launched.
Structure of packages with tests:
5cab5bc113b45493953992.png

Answer the question

In order to leave comments, you need to log in

1 answer(s)
M
MoOFueL, 2019-04-09
@MoOFueL

@WebMvcTest implements the so-called. testing by layers of a Spring application, namely, it does not load extra beans and configurations that are not needed in this type of test. Because of this, @ControllerAdvice are not automatically loaded into the context.
There are two solutions to choose from: a normal integration test (@SpringBootTest, etc.) with a call to the controller via RestTemplate or using MockMvcBuilder to configure MockMvc (rather than injection via @Autowired), in which you can specify which advises are needed for this test.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question