web-dev-qa-db-ger.com

So überprüfen Sie String im Antworttext mit mockMvc

Ich habe einen einfachen Integrationstest

    @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 der letzten Zeile möchte ich die im Antworttext empfangene Zeichenfolge mit der erwarteten Zeichenfolge vergleichen

Und als Antwort bekomme ich:

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

Versuchte ein paar Tricks mit content (), body (), aber nichts hat funktioniert.

194
pbaranski

@Sotirios Delimanolis Antwort mache den Job, aber ich habe nach einem Vergleich von Strings innerhalb dieser mockMvc-Behauptung gesucht

Hier ist es also

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

Natürlich scheitert meine Behauptung:

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

da:

  MockHttpServletResponse:
            Body = "Something gone wrong"

Das ist also der Beweis, dass es funktioniert!

87
pbaranski

Sie können andReturn() aufrufen und das zurückgegebene MvcResult -Objekt verwenden, um den Inhalt als String abzurufen.

Siehe unten:

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
297

Spring MockMvc unterstützt jetzt JSON direkt. Also sagst du einfach:

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

und im Gegensatz zum Zeichenfolgenvergleich wird hier so etwas wie "fehlendes Feld xyz" oder "Nachricht erwartet" ok "hat" nok ".

Diese Methode wurde im Frühjahr 4.1 eingeführt.

55
vertti

Wenn ich diese Antworten lese, sehe ich viel in Bezug auf Spring Version 4.x. Ich verwende Version 3.2.0 aus verschiedenen Gründen. Dinge wie die json-Unterstützung direkt aus der content() ist also nicht möglich.

Ich fand das mit MockMvcResultMatchers.jsonPath ist wirklich einfach und funktioniert ein Vergnügen. Hier ist ein Beispiel für das Testen einer Post-Methode.

Der Vorteil dieser Lösung besteht darin, dass Sie immer noch Attribute abgleichen und sich nicht auf vollständige JSON-Zeichenfolgenvergleiche verlassen.

(Mit 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));

Der Anfragetext war nur eine JSON-Zeichenfolge, die Sie leicht aus einer echten JSON-Scheindatei laden können, wenn Sie dies wünschen, aber ich habe das hier nicht angegeben, da es von der Frage abgewichen wäre.

Der tatsächlich zurückgegebene json hätte folgendermaßen ausgesehen:

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

Frühling Sicherheit ist @WithMockUser und hamcrests containsString Matcher ergeben eine einfache und elegante Lösung:

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

Weitere Beispiele auf Github

19
Michael W

Entnommen aus dem Frühjahr Tutorial

    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 ist verfügbar bei import static org.hamcrest.Matchers.*;

jsonPath ist verfügbar bei import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;

und jsonPath Referenz kann gefunden werden hier

19
user2829759

hier eine elegantere Art und Weise

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()

Dies sollte Ihnen den Hauptteil der Antwort geben. "Benutzername bereits vergeben" in Ihrem Fall.

1
justAnotherGuy

Hier ist ein Beispiel, wie Sie eine JSON-Antwort analysieren und sogar eine Anfrage mit einem Bean in JSON-Form senden:

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

Wie Sie hier sehen können, ist Book ein Request-DTO und UpdateBookResponse ein von JSON geparstes Antwortobjekt. Möglicherweise möchten Sie die Konfiguration von Jakson ObjectMapper ändern.

0
stokito