@MaxLich
java developer

Как протестировать контроллер вместе с отловом ошибок через ControllerAdvice?

Здравствуйте. Использую spring 5 вместе со spring boot 5, junit 5, mvc. Необходимо протестировать контроллер вместе с классом, помеченным аннотацией @ControllerAdvice. Мой класс с тестами:
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");

    }


И класса ControllerAdvice:
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());
    }
}

Проблема в том, что во время тестов он не заходит ни в один из методов класса ControllerAdvice. Хотя при реальной работе программы соответствующие методы этого класса запускаются.
Структура пакетов с тестами:
5cab5bc113b45493953992.png
  • Вопрос задан
  • 553 просмотра
Пригласить эксперта
Ответы на вопрос 1
@MoOFueL
@WebMvcTest реализует т.н. тестирование по слоям Spring-приложения, а именно - не загружает лишние бины и конфигурации, которые не нужны в данном виде теста. Из-за этого @ControllerAdvice автоматически не загружаются в контекст.
Тут на выбор два решения: нормальный интеграционный тест(@SpringBootTest и тд) с вызовом контроллера через RestTemplate либо использование MockMvcBuilder для настройки MockMvc(а не инжект через @Autowired), в котором вы можете указать, какие эдвайсы нужны для этого теста.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы