web-dev-qa-db-ja.com

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()でいくつかのトリックを試しましたが、何もうまくいきませんでした。

179
pbaranski

@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"

だから、これはそれが動作することの証明です!

81
pbaranski

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
281

Spring MockMvcは現在JSONを直接サポートしています。だからあなたはただ言う:

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

文字列の比較とは異なり、 "missing field xyz"や "message Expected 'ok' got 'nok'のようになります。

このメソッドはSpring 4.1で導入されました。

53
vertti

これらの答えを読んで、私は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モックデータファイルから簡単にロードできますが、質問から逸脱しているため、ここには含めませんでした。

実際に返されるJSONは、次のようになります。

{
    "data":"some value"
}
40
Jeremy

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

githubに関するその他の例

17
Michael W

春の チュートリアルから取りました

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

isimport static org.hamcrest.Matchers.*;から入手できます。

jsonPathimport static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;から入手できます。

そしてjsonPath参照はここで見つけることができます

17
user2829759

ここでよりエレガントな方法

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

これはあなたに応答の本体を与えるべきです。あなたの場合は「ユーザー名は既に使用されています」。

1
justAnotherGuy

JSON応答を解析する方法、およびJSON形式のBeanを使用してリクエストを送信する方法の例を次に示します。

  @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構成を変更することもできます。

0
stokito