How to check String in response body with mockMvc

JavaSpringMockingSpring Test-Mvc

Java Problem Overview


I have simple integration test

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

In last line I want to compare string received in response body to expected string

And in response I get:

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

Tried some tricks with content(), body() but nothing worked.

Java Solutions


Solution 1 - Java

You can call andReturn() and use the returned MvcResult object to get the content as a String.

See below:

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 

Solution 2 - Java

@Sotirios Delimanolis answer do the job however I was looking for comparing strings within this mockMvc assertion

So here it is

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

Of course my assertion fail:

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

because:

  MockHttpServletResponse:
            Body = "Something gone wrong"

So this is proof that it works!

Solution 3 - Java

Spring MockMvc now has direct support for JSON. So you just say:

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

and unlike string comparison, it will say something like "missing field xyz" or "message Expected 'ok' got 'nok'.

This method was introduced in Spring 4.1.

Solution 4 - Java

Reading these answers, I can see a lot relating to Spring version 4.x, I am using version 3.2.0 for various reasons. So things like json support straight from the content() is not possible.

I found that using MockMvcResultMatchers.jsonPath is really easy and works a treat. Here is an example testing a post method.

The bonus with this solution is that you're still matching on attributes, not relying on full json string comparisons.

(Using 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));

The request body was just a json string, which you can easily load from a real json mock data file if you wanted, but I didnt include that here as it would have deviated from the question.

The actual json returned would have looked like this:

{
    "data":"some value"
}

Solution 5 - Java

Taken from spring's tutorial

mockMvc.perform(get("/" + 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 is available from import static org.hamcrest.Matchers.*;

jsonPath is available from import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

and jsonPath reference can be found here

Solution 6 - Java

Spring security's @WithMockUser and hamcrest's containsString matcher makes for a simple and elegant solution:

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

More examples on github

Solution 7 - Java

here a more elegant way

mockMvc.perform(post("/retrieve?page=1&countReg=999999")
            .header("Authorization", "Bearer " + validToken))
            .andExpect(status().isOk())
            .andExpect(content().string(containsString("regCount")));

Solution 8 - Java

Here is an example how to parse JSON response and even how to send a request with a bean in JSON form:

  @Autowired
  protected MockMvc mvc;

  private static final ObjectMapper MAPPER = new ObjectMapper()
    .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    .registerModule(new JavaTimeModule());

  public static String requestBody(Object request) {
    try {
      return MAPPER.writeValueAsString(request);
    } catch (JsonProcessingException e) {
      throw new RuntimeException(e);
    }
  }

  public static <T> T parseResponse(MvcResult result, Class<T> responseClass) {
    try {
      String contentAsString = result.getResponse().getContentAsString();
      return MAPPER.readValue(contentAsString, responseClass);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  @Test
  public void testUpdate() {
    Book book = new Book();
    book.setTitle("1984");
    book.setAuthor("Orwell");
    MvcResult requestResult = mvc.perform(post("http://example.com/book/")
      .contentType(MediaType.APPLICATION_JSON)
      .content(requestBody(book)))
      .andExpect(status().isOk())
      .andReturn();
    UpdateBookResponse updateBookResponse = parseResponse(requestResult, UpdateBookResponse.class);
    assertEquals("1984", updateBookResponse.getTitle());
    assertEquals("Orwell", updateBookResponse.getAuthor());
  }

As you can see here the Book is a request DTO and the UpdateBookResponse is a response object parsed from JSON. You may want to change the Jackson's ObjectMapper configuration.

Solution 9 - Java

One possible approach is to simply include gson dependency:

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

and parse the value to make your verifications:

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

Solution 10 - Java

Another option is:

when:

def response = mockMvc.perform(
            get('/path/to/api')
            .header("Content-Type", "application/json"))

then:

response.andExpect(status().isOk())
response.andReturn().getResponse().getContentAsString() == "what you expect"

Solution 11 - Java

You can use getContentAsString method to get the response data as string.

    String payload = "....";
    String apiToTest = "....";
    
    MvcResult mvcResult = mockMvc.
    			perform(post(apiToTest).
    			content(payload).
    			contentType(MediaType.APPLICATION_JSON)).
    			andReturn();
    
    String responseData = mvcResult.getResponse().getContentAsString();

You can refer this link for test application.

Solution 12 - Java

String body = mockMvc.perform(bla... bla).andReturn().getResolvedException().getMessage()

This should give you the body of the response. "Username already taken" in your case.

Solution 13 - Java

Another example is:

.andExpect(jsonPath("$").value(containsString("You have successfully deleted")));

The body response:

Body = You have successfully deleted a [Object] with ID: 1

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionpbaranskiView Question on Stackoverflow
Solution 1 - JavaSotirios DelimanolisView Answer on Stackoverflow
Solution 2 - JavapbaranskiView Answer on Stackoverflow
Solution 3 - JavaverttiView Answer on Stackoverflow
Solution 4 - JavaJeremyView Answer on Stackoverflow
Solution 5 - Javauser2829759View Answer on Stackoverflow
Solution 6 - JavaMichael WView Answer on Stackoverflow
Solution 7 - JavaRicardo RibeiroView Answer on Stackoverflow
Solution 8 - JavaSergey PonomarevView Answer on Stackoverflow
Solution 9 - JavaKoray TugayView Answer on Stackoverflow
Solution 10 - JavaDaniel Vilas-BoasView Answer on Stackoverflow
Solution 11 - JavaHari KrishnaView Answer on Stackoverflow
Solution 12 - JavajustAnotherGuyView Answer on Stackoverflow
Solution 13 - JavaNXT DevView Answer on Stackoverflow