簡単な統合テストがあります
@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()でいくつかのトリックを試しましたが、何もうまくいきませんでした。
@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"
だから、これはそれが動作することの証明です!
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
Spring MockMvcは現在JSONを直接サポートしています。だからあなたはただ言う:
.andExpect(content().json("{'message':'ok'}"));
文字列の比較とは異なり、 "missing field xyz"や "message Expected 'ok' got 'nok'のようになります。
このメソッドはSpring 4.1で導入されました。
これらの答えを読んで、私は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"
}
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.")));
}
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
参照はここで見つけることができます
ここでよりエレガントな方法
mockMvc.perform(post("/retrieve?page=1&countReg=999999")
.header("Authorization", "Bearer " + validToken))
.andExpect(status().isOk())
.andExpect(content().string(containsString("regCount")));
String body = mockMvc.perform(bla... bla).andReturn().getResolvedException().getMessage()
これはあなたに応答の本体を与えるべきです。あなたの場合は「ユーザー名は既に使用されています」。
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
構成を変更することもできます。