Как проверить строку в тело ответа с помощью 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
Пробовал некоторые трюки с контентом(), body(), но ничего не получилось.
Ответы
Ответ 1
@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"
Итак, это доказательство того, что он работает!
Ответ 2
Вы можете вызвать 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(MockMvcResultHandlers.print())
.andExpect(status().isBadRequest())
.andReturn();
String content = result.getResponse().getContentAsString();
// do what you will
Ответ 3
Spring Теперь MockMvc имеет прямую поддержку JSON. Поэтому вы просто говорите:
.andExpect(content().json("{'message':'ok'}"));
и, в отличие от сравнения строк, он скажет что-то вроде "отсутствует поле xyz" или "сообщение" Ожидаемое "ok 'got' nok '.
Этот метод был введен в Spring 4.1.
Ответ 4
Читая эти ответы, я вижу много, относящихся к Spring версии 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 data, если хотите, но я не включил его здесь, поскольку он отклонился бы от вопроса.
Фактический ответ json выглядел бы так:
{
"data":"some value"
}
Ответ 5
Spring security @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
Ответ 6
Взято из весеннего урока
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
можно найти здесь
Ответ 7
String body = mockMvc.perform(bla... bla).andReturn().getResolvedException().getMessage()
Это должно дать вам ответ. "Имя пользователя уже выполнено" в вашем случае.
Ответ 8
здесь более элегантный способ
mockMvc.perform(post("/retrieve?page=1&countReg=999999")
.header("Authorization", "Bearer " + validToken))
.andExpect(status().isOk())
.andExpect(content().string(containsString("regCount")));
Ответ 9
Вот пример того, как проанализировать ответ JSON и даже как отправить запрос с bean-компонентом в форме JSON:
@Autowired
protected MockMvc mvc;
private static final ObjectMapper MAPPER = new ObjectMapper()
.configure(WRITE_DATES_AS_TIMESTAMPS, false)
.configure(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());
}
Как вы можете видеть здесь, Book
является запросом DTO, а UpdateBookResponse
является объектом ответа, анализируемым из JSON. Вы можете изменить конфигурацию Jakson ObjectMapper
.