Cómo verificar String en el cuerpo de respuesta con mockMvc

5 minutos de lectura

avatar de usuario
pbaranski

Tengo una prueba de integración simple.

@Test
public void shouldReturnErrorMessageToAdminWhenCreatingUserWithUsedUserName() throws Exception {
    mockMvc.perform(post("/api/users").header("Authorization", base64ForTestUser).contentType(MediaType.APPLICATION_JSON)
        .content("{\"userName\":\"testUserDetails\",\"firstName\":\"xxx\",\"lastName\":\"xxx\",\"password\":\"xxx\"}"))
        .andDo(print())
        .andExpect(status().isBadRequest())
        .andExpect(?);
}

En la última línea, quiero comparar la cadena recibida en el cuerpo de respuesta con la cadena esperada

Y como respuesta obtengo:

MockHttpServletResponse:
          Status = 400
   Error message = null
         Headers = {Content-Type=[application/json]}
    Content type = application/json
            Body = "Username already taken"
   Forwarded URL = null
  Redirected URL = null

Intenté algunos trucos con content(), body() pero nada funcionó.

  • Solo como consejo, el código de estado 400 no debe devolverse para algo como "Username already taken". Eso debería ser más un conflicto 409.

    – Sotirios Delimanolis

    20 de agosto de 2013 a las 13:33

  • Gracias: el objetivo de esta prueba es especificar tales cosas.

    – pbaranski

    20 de agosto de 2013 a las 17:21

avatar de usuario
Sotirios Delimanolis

Puedes llamar andReturn() y usar el devuelto MvcResult objeto para obtener el contenido como un String.

Vea abajo:

MvcResult result = mockMvc.perform(post("/api/users").header("Authorization", base64ForTestUser).contentType(MediaType.APPLICATION_JSON)
            .content("{\"userName\":\"testUserDetails\",\"firstName\":\"xxx\",\"lastName\":\"xxx\",\"password\":\"xxx\"}"))
            .andDo(MockMvcResultHandlers.print())
            .andExpect(status().isBadRequest())
            .andReturn();

String content = result.getResponse().getContentAsString();
// do what you will 

La respuesta de @Sotirios Delimanolis hace el trabajo, sin embargo, estaba buscando cadenas de comparación dentro de esta afirmación de mockMvc

Asi que aqui esta

.andExpect(content().string("\"Username already taken - please try with different username\""));

Por supuesto, mi afirmación falla:

java.lang.AssertionError: Response content expected:
<"Username already taken - please try with different username"> but was:<"Something gone wrong">

porque:

  MockHttpServletResponse:
            Body = "Something gone wrong"

¡Así que esta es una prueba de que funciona!

  • En caso de que alguien tenga mensajes con identificaciones dinámicas, como yo, es útil saber que el método string() también acepta un hamcrest contieneCadena emparejador: .andExpect(content().string(containsString("\"Username already taken");

    – Molholm

    26 mayo 2014 a las 12:14

  • @TimBüthe, eso es incorrecto. Si tiene un problema de este tipo, debe publicarlo como una pregunta porque definitivamente ese no es el comportamiento esperado ni es un comportamiento que he presenciado en mi propio código.

    – Pablo

    10 de diciembre de 2014 a las 18:58

  • Solo tenga en cuenta que la importación es org.hamcrest.Matchers.containsString().

    – sonido de los miembros

    16 de diciembre de 2019 a las 11:44

  • también usé org.hamcrest.Matchers.equalToIgnoringWhiteSpace() matcher para ignorar todos los espacios en blanco. Tal vez sea un consejo útil para alguien.

    –Iwo Kucharski

    9 de abril de 2020 a las 12:43

avatar de usuario
vertti

Spring MockMvc ahora tiene soporte directo para JSON. Así que solo dices:

.andExpect(content().json("{'message':'ok'}"));

y a diferencia de la comparación de cadenas, dirá algo como “campo faltante xyz” o “mensaje esperado ‘ok’ obtuvo ‘nok’.

Este método se introdujo en Spring 4.1.

  • ¿Podría proporcionar un ejemplo completo? no necesita ContentRequestMatchers para apoyar esta función también?

    – Zaratustra

    17 de julio de 2015 a las 10:21

avatar de usuario
jeremy

Al leer estas respuestas, puedo ver muchas cosas relacionadas con Spring versión 4.x, estoy usando la versión 3.2.0 por varias razones. Por lo tanto, cosas como la compatibilidad con json directamente desde el content() no es posible.

Descubrí que usando MockMvcResultMatchers.jsonPath es muy fácil y funciona de maravilla. Aquí hay un ejemplo que prueba un método de publicación.

La ventaja de esta solución es que todavía está haciendo coincidir los atributos, sin depender de las comparaciones completas de cadenas json.

(Usando org.springframework.test.web.servlet.result.MockMvcResultMatchers)

String expectedData = "some value";
mockMvc.perform(post("/endPoint")
                .contentType(MediaType.APPLICATION_JSON)
                .content(mockRequestBodyAsString.getBytes()))
                .andExpect(status().isOk())
                .andExpect(MockMvcResultMatchers.jsonPath("$.data").value(expectedData));

El cuerpo de la solicitud era solo una cadena json, que puede cargar fácilmente desde un archivo de datos simulado json real si lo desea, pero no lo incluí aquí porque se habría desviado de la pregunta.

El json real devuelto se habría visto así:

{
    "data":"some value"
}

avatar de usuario
usuario2829759

Tomado de la primavera tutorial

mockMvc.perform(get("https://stackoverflow.com/" + userName + "/bookmarks/" 
    + this.bookmarkList.get(0).getId()))
    .andExpect(status().isOk())
    .andExpect(content().contentType(contentType))
    .andExpect(jsonPath("$.id", is(this.bookmarkList.get(0).getId().intValue())))
    .andExpect(jsonPath("$.uri", is("http://bookmark.com/1/" + userName)))
    .andExpect(jsonPath("$.description", is("A description")));

is está disponible desde import static org.hamcrest.Matchers.*;

jsonPath está disponible desde import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

y jsonPath se puede encontrar la referencia aquí

  • yo obtengo error: incompatible types: RequestMatcher cannot be converted to ResultMatcher por .andExpect(content().contentType(contentType))

    – Ian Vaughan

    1 de febrero de 2019 a las 14:30

  • @IanVaughan MockMvcResultMatchers.content().contentType(contentType)

    – Rajkumar

    13 de febrero de 2020 a las 17:09


avatar de usuario
miguel w

primavera de seguridad @WithMockUser y Hamcrest’s containsString matcher es una solución simple y elegante:

@Test
@WithMockUser(roles = "USER")
public void loginWithRoleUserThenExpectUserSpecificContent() throws Exception {
    mockMvc.perform(get("/index"))
            .andExpect(status().isOk())
            .andExpect(content().string(containsString("This content is only shown to users.")));
}

Más ejemplos en github

  • yo obtengo error: incompatible types: RequestMatcher cannot be converted to ResultMatcher por .andExpect(content().contentType(contentType))

    – Ian Vaughan

    1 de febrero de 2019 a las 14:30

  • @IanVaughan MockMvcResultMatchers.content().contentType(contentType)

    – Rajkumar

    13 de febrero de 2020 a las 17:09


Un enfoque posible es simplemente incluir gson dependencia:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
</dependency>

y analice el valor para hacer sus verificaciones:

@RunWith(SpringRunner.class)
@WebMvcTest(HelloController.class)
public class HelloControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private HelloService helloService;

    @Before
    public void before() {
        Mockito.when(helloService.message()).thenReturn("hello world!");
    }

    @Test
    public void testMessage() throws Exception {
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/"))
                .andExpect(status().isOk())
                .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE))
                .andReturn();

        String responseBody = mvcResult.getResponse().getContentAsString();
        ResponseDto responseDto
                = new Gson().fromJson(responseBody, ResponseDto.class);
        Assertions.assertThat(responseDto.message).isEqualTo("hello world!");
    }
}

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad