Réutiliser Spring Boot ErrorAttributes lors de l'utilisation de MockMvc et Spring REST Docs


Rasmus Sjørslev

J'écris des tests pour un contrôleur qui lève une exception personnalisée ( AuthenticationExceptiondans mon cas) qui est annotée avec@ResponseStatus(value = HttpStatus.BAD_REQUEST)

L'appel du point de terminaison qui lève l'exception à l'aide de ie curl fonctionne correctement et j'obtiens le résultat attendu avec un exemple ci-dessous :

{
  "timestamp": 1494185397677,
  "status": 400,
  "error": "Bad Request",
  "exception": "com.example.exception.AuthenticationException",
  "message": "These are not the credentials you are looking for",
  "path": "/status/throw/2"
}

Lorsque j'écris un test pour cela avec Mockito qui utilise, willThrow()je n'obtiens aucune des sorties générées par Spring Boot, mais uniquement le code de réponse annoté dans ma classe d'exception.

Voici mon essai :

@Test
public void throwsShouldShowResponseBody() throws Exception {
    given(this.service.getAccStatus())
            .willThrow(AuthenticationException.class);

    this.mvc.perform(get("/status/throw/2"))
            .andExpect(status().isBadRequest())
            .andDo(document("bad-credentials"));
}

En regardant des questions similaires, il semble que cela puisse être causé par le fait que MockMvc ne suit pas les redirections que Spring Boot utilise pour pousser vers / error, mais ma demande est de savoir s'il existe de toute façon, je peux faire fonctionner cela afin que je n'aie pas à écrire de @ControllerAdviceclasse avec quelque chose similaire à ce ErrorAttributesque Spring Boot fournit déjà. Je ne souhaite pas modifier la sortie générée par Spring Boot en cas d'erreur.

Merci -

Andy Wilkinson

Comme vous l'avez noté, il est un peu difficile de documenter la réponse d'erreur de Spring Boot lors de l'utilisation de MockMvc. En effet, Spring Boot transmet la demande au contrôleur d'erreur qui est mappé /erroret MockMvcne traite pas les transferts par défaut.

Une façon de documenter une réponse d'erreur consiste à appeler /errordirectement avec une requête configurée de manière appropriée. Il y a un exemple de cela dans l'un des exemples de Spring REST Docs :

@Test
public void errorExample() throws Exception {
    this.mockMvc
        .perform(get("/error")
            .requestAttr(RequestDispatcher.ERROR_STATUS_CODE, 400)
            .requestAttr(RequestDispatcher.ERROR_REQUEST_URI, "/notes")
            .requestAttr(RequestDispatcher.ERROR_MESSAGE, "The tag 'http://localhost:8080/tags/123' does not exist"))
        .andExpect(status().isBadRequest())
        .andExpect(jsonPath("error", is("Bad Request")))
        .andExpect(jsonPath("timestamp", is(notNullValue())))
        .andExpect(jsonPath("status", is(400)))
        .andExpect(jsonPath("path", is(notNullValue())))
        .andDo(this.documentationHandler.document(
            responseFields(
                fieldWithPath("error").description("The HTTP error that occurred, e.g. `Bad Request`"),
                fieldWithPath("message").description("A description of the cause of the error"),
                fieldWithPath("path").description("The path to which the request was made"),
                fieldWithPath("status").description("The HTTP status code, e.g. `400`"),
                fieldWithPath("timestamp").description("The time, in milliseconds, at which the error occurred"))));
}

Il est ensuite utilisé dans la documentation résultante pour décrire le format de réponse d'erreur utilisé dans l'ensemble de l'API.

Articles connexes


Spring-Boot et Spock échouent lors de l'utilisation de Unroll

BramP Je mets en place un projet de démonstration avec Spring-Boot. Pour la persistance des entités, j'utilise des implémentations de référentiel générées par Spring basées sur des interfaces: @Repository public interface MovieRepository extends JpaRepository<