Testen von Ausnahmen mit Spring MockMvc

1. Übersicht

In diesem kurzen Artikel erfahren Sie, wie Ausnahmen in unseren Controllern ausgelöst werden sollen und wie diese Ausnahmen mit Spring MockMvc getestet werden.

2. Ausnahmen in Controllern auslösen

Lassen Sie uns lernen, wie Sie eine Ausnahme von einem Controller aus starten .

Wir können uns die Dienste, die wir von einem Controller bereitstellen, genauso vorstellen, als wären sie normale Java-Funktionen:

@GetMapping("/exception/throw") public void getException() throws Exception { throw new Exception("error"); } 

Nun wollen wir sehen, was passiert, wenn wir diesen Dienst aufrufen. Zunächst werden wir feststellen, dass der Antwortcode des Dienstes 500 lautet, was einen internen Serverfehler bedeutet.

Zweitens erhalten wir eine Antwortstelle wie diese:

{ "timestamp": 1592074599854, "status": 500, "error": "Internal Server Error", "message": "No message available", "trace": "java.lang.Exception at com.baeldung.controllers.ExceptionController.getException(ExceptionController.java:26) ..." }

Wenn wir eine Ausnahme von einem RestController auslösen , wird die Serviceantwort automatisch einem 500-Antwortcode zugeordnet, und die Stapelverfolgung der Ausnahme wird in den Antworttext aufgenommen.

3. Zuordnen von Ausnahmen zu HTTP-Antwortcodes

Jetzt lernen wir, wie wir unsere Ausnahmen anderen Antwortcodes als 500 zuordnen können.

Um dies zu erreichen, erstellen wir benutzerdefinierte Ausnahmen und verwenden die von Spring bereitgestellte ResponseStatus- Annotation. Lassen Sie uns diese benutzerdefinierten Ausnahmen erstellen:

@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); } }

Der zweite und letzte Schritt besteht darin, einen einfachen Dienst in unserem Controller zu erstellen, um diese Ausnahmen auszulösen:

@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"); } }

Lassen Sie uns nun die unterschiedlichen Antworten des Dienstes für die verschiedenen Ausnahmen sehen, die wir zugeordnet haben:

  • Für not_found erhalten wir einen Antwortcode von 404
  • Bei dem Wert bad_arguments erhalten wir einen Antwortcode von 400
  • Für jeden anderen Wert erhalten wir weiterhin 500 als Antwortcode

Abgesehen von den Antwortcodes erhalten wir einen Textkörper mit demselben Format wie der im vorherigen Abschnitt empfangene Antworttext.

4. Testen unserer Controller

Schließlich werden wir sehen, wie wir testen können, ob unser Controller die richtigen Ausnahmen auslöst .

Der erste Schritt besteht darin, eine Testklasse und eine Instanz von MockMvc zu erstellen :

@Autowired private MockMvc mvc; 

Als Nächstes erstellen wir die Testfälle für jeden der Werte, die unser Service erhalten kann:

@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())); }

Mit diesen Tests überprüfen wir, ob der Antwortcode, der Typ der ausgelösten Ausnahme und die Meldungen dieser Ausnahmen die erwarteten für jeden der Werte sind.

5. Schlussfolgerung

In diesem Tutorial haben wir gelernt, wie Sie mit Ausnahmen in unseren Spring RestControllern umgehen und wie Sie testen, ob jeder exponierte Dienst die erwarteten Ausnahmen auslöst .

Wie immer ist der vollständige Quellcode des Artikels in GitHub verfügbar.