Как проверить строку в тело ответа с mockMvc

у меня есть простой интеграционного тестирования

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

в последней строке я хочу сравнить строку, полученную в теле ответа, с ожидаемой строкой

и в ответ получаю:

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

пробовал некоторые трюки с content (), body (), но ничего не получилось.

8 ответов


можно назвать andReturn() и использовать возвращенный MvcResult объект для получения содержимого как String. См. ниже:

MvcResult result = 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())
            .andReturn();

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

@Sotirios Delimanolis ответ сделайте работу, однако я искал сравнение строк в этом утверждении mockMvc

вот это

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

конечно, мое утверждение не выполнено:

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

потому что:

  MockHttpServletResponse:
            Body = "Something gone wrong"

Так это доказательство того, что он работает!


Spring MockMvc теперь имеет прямую поддержку JSON. Поэтому вы просто говорите:

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

и в отличие от сравнения строк, он скажет что-то вроде "отсутствует поле xyz" или "сообщение ожидается" ОК "получил " nok".

этот метод был введен весной 4.1.


читая эти ответы, я вижу много, относящегося к весенней версии 4.x, я использую версию 3.2.0 по разным причинам. Так что такие вещи, как поддержка json прямо из content() не возможно.

я обнаружил, что с помощью MockMvcResultMatchers.jsonPath - Это очень легко и работает хорошо. Вот пример тестирования метода post.

бонус с этим решением заключается в том, что вы все еще соответствуете атрибутам, не полагаясь на полные сравнения строк json.

(используя 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));

тело запроса было просто строкой json, которую вы можете легко загрузить из реального файла данных JSON mock, если хотите, но я не включил это здесь, поскольку это отклонялось бы от вопроса.

фактическое возвращение json выглядело бы так:

{
    "data":"some value"
}

Весенняя безопасность @WithMockUser и hamcrest по containsString matcher делает для простого и элегантного решения:

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

больше примеров на github


взята с весны учебник

    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 доступно import static org.hamcrest.Matchers.*;

jsonPath доступно import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

и jsonPath ссылка может быть найдена здесь


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

Это должно дать вам тело ответа. "Имя пользователя уже занято" в вашем случае.


для проверки конечного результата html вы можете получить весь вывод HTML кодом ниже и проверить сообщения в нем:

@Test
public void testHtmlOutput() throws Exception {
    String htmlBody = this.restTemplate.getForObject("/mypage, String.class);
    assertThat(htmlBody.contains("any message in html output"));
}

шаблон rest должен быть autowired:

@Autowired
private TestRestTemplate restTemplate;

и assertThat должен быть импортирован как статический метод:

import static org.assertj.core.api.Assertions.assertThat;