1. Обзор
В этой короткой статье мы увидим, как должны создаваться исключения в наших контроллерах и как тестировать эти исключения с помощью Spring MockMvc.
2. Генерация исключений в контроллерах
Давайте начнем изучать , как запустить исключение из контроллера .
Мы можем думать о службах, которые мы предоставляем из контроллера, так же, как если бы они были обычными функциями Java:
@GetMapping("/exception/throw")
public void getException() throws Exception {
throw new Exception("error");
}
Теперь давайте посмотрим, что происходит, когда мы вызываем эту службу. Во-первых, мы заметим, что код ответа службы — 500, что означает внутреннюю ошибку сервера.
Во-вторых, мы получаем тело ответа, подобное этому:
{
"timestamp": 1592074599854,
"status": 500,
"error": "Internal Server Error",
"message": "No message available",
"trace": "java.lang.Exception
at com.foreach.controllers.ExceptionController.getException(ExceptionController.java:26)
..."
}
В заключение, когда мы выбрасываем исключение из RestController
, ответ службы автоматически сопоставляется с кодом ответа 500, а трассировка стека исключения включается в тело ответа.
3. Сопоставление исключений с кодами ответов HTTP
Теперь мы собираемся узнать , как сопоставить наши исключения с другими кодами ответов, отличными от 500.
Для этого мы собираемся создать собственные исключения и использовать аннотацию ResponseStatus
, предоставленную Spring. Давайте создадим эти пользовательские исключения:
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class BadArgumentsException extends RuntimeException {
public BadArgumentsException(String message) {
super(message);
}
}
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public class InternalException extends RuntimeException {
public InternalException(String message) {
super(message);
}
}
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
Второй и последний шаг — создать простую службу в нашем контроллере, чтобы генерировать эти исключения:
@GetMapping("/exception/{exception_id}")
public void getSpecificException(@PathVariable("exception_id") String pException) {
if("not_found".equals(pException)) {
throw new ResourceNotFoundException("resource not found");
}
else if("bad_arguments".equals(pException)) {
throw new BadArgumentsException("bad arguments");
}
else {
throw new InternalException("internal error");
}
}
Теперь давайте посмотрим на разные ответы службы для разных исключений, которые мы сопоставили:
- Для
not_found
мы получаем код ответа 404. - Учитывая значение
bad_arguments
, мы получаем код ответа 400 - Для любого другого значения мы все равно получим 500 в качестве кода ответа.
Помимо кодов ответа, мы получим тело в том же формате, что и тело ответа, полученное в предыдущем разделе.
4. Тестирование наших контроллеров
Наконец, мы увидим, как проверить, что наш контроллер генерирует правильные исключения .
Первый шаг — создать тестовый класс и создать экземпляр MockMvc
:
@Autowired
private MockMvc mvc;
Далее давайте создадим тестовые примеры для каждого из значений, которые может получить наш сервис:
@Test
public void givenNotFound_whenGetSpecificException_thenNotFoundCode() throws Exception {
String exceptionParam = "not_found";
mvc.perform(get("/exception/{exception_id}", exceptionParam)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isNotFound())
.andExpect(result -> assertTrue(result.getResolvedException() instanceof ResourceNotFoundException))
.andExpect(result -> assertEquals("resource not found", result.getResolvedException().getMessage()));
}
@Test
public void givenBadArguments_whenGetSpecificException_thenBadRequest() throws Exception {
String exceptionParam = "bad_arguments";
mvc.perform(get("/exception/{exception_id}", exceptionParam)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest())
.andExpect(result -> assertTrue(result.getResolvedException() instanceof BadArgumentsException))
.andExpect(result -> assertEquals("bad arguments", result.getResolvedException().getMessage()));
}
@Test
public void givenOther_whenGetSpecificException_thenInternalServerError() throws Exception {
String exceptionParam = "dummy";
mvc.perform(get("/exception/{exception_id}", exceptionParam)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isInternalServerError())
.andExpect(result -> assertTrue(result.getResolvedException() instanceof InternalException))
.andExpect(result -> assertEquals("internal error", result.getResolvedException().getMessage()));
}
С помощью этих тестов мы проверяем, что код ответа, тип возбуждаемого исключения и сообщения об этих исключениях являются ожидаемыми для каждого из значений.
5. Вывод
В этом руководстве мы узнали, как обрабатывать исключения в наших Spring RestController
s и как проверить, что каждая открытая служба выдает ожидаемые исключения.
Как всегда, полный исходный код статьи доступен на GitHub .