Java 如何使用mockMvc检查响应正文中的字符串

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18336277/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:39:34  来源:igfitidea点击:

How to check String in response body with mockMvc

javaspringmockingspring-test-mvc

提问by pbaranski

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.

用 content(), body() 尝试了一些技巧,但没有任何效果。

采纳答案by pbaranski

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

@Sotirios Delimanolis 回答完成了这项工作,但是我正在寻找在这个 mockMvc 断言中比较字符串

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!

所以这证明它有效!

回答by Sotirios Delimanolis

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

您可以调用andReturn()并使用返回的MvcResult对象将内容作为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 

回答by vertti

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

Spring MockMvc 现在直接支持 JSON。所以你只要说:

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

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

与字符串比较不同的是,它会说“缺少字段 xyz”或“消息预期 'ok' 得到 'nok'。

This method was introduced in Spring 4.1.

这个方法是在 Spring 4.1 中引入的。

回答by justAnotherGuy

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

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

这应该给你响应的正文。在您的情况下,“用户名已被占用”。

回答by Jeremy

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.

阅读这些答案,我可以看到很多与 Spring 4.x 版相关的内容,出于各种原因,我正在使用 3.2.0 版。所以像 json 直接支持这样的事情content()是不可能的。

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

我发现使用MockMvcResultMatchers.jsonPath真的很容易,而且效果很好。这是一个测试 post 方法的示例。

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

这个解决方案的好处是你仍然匹配属性,而不是依赖于完整的 json 字符串比较。

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

(使用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.

请求正文只是一个 json 字符串,如果需要,您可以轻松地从真正的 json 模拟数据文件中加载它,但我没有在此处包含它,因为它会偏离问题。

The actual json returned would have looked like this:

返回的实际 json 看起来像这样:

{
    "data":"some value"
}

回答by Michael W

Spring security's @WithMockUserand hamcrest's containsStringmatcher makes for a simple and elegant solution:

Spring security@WithMockUser和 hamcrest 的containsString匹配器提供了一个简单而优雅的解决方案:

@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

github 上的更多示例

回答by user2829759

Taken from spring's tutorial

取自 spring 的教程

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")));

isis available from import static org.hamcrest.Matchers.*;

is可从 import static org.hamcrest.Matchers.*;

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

jsonPath可从 import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

and jsonPathreference can be found here

jsonPath参考可以在这里找到

回答by Ricardo Ribeiro

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")));

回答by Sergey Ponomarev

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

这是一个如何解析 JSON 响应,甚至如何使用 JSON 形式的 bean 发送请求的示例:

  @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 Bookis a request DTO and the UpdateBookResponseis a response object parsed from JSON. You may want to change the Jakson's ObjectMapperconfiguration.

正如您在此处看到的,这Book是一个请求 DTO,而UpdateBookResponse是从 JSON 解析的响应对象。您可能想要更改 Jakson 的ObjectMapper配置。

回答by Hari Krishna

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

您可以使用 'getContentAsString' 方法以字符串形式获取响应数据。

    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 linkfor test application.

您可以参考此链接进行测试应用程序。