MockMvc के साथ प्रतिक्रिया शरीर में स्ट्रिंग की जांच कैसे करें


243

मेरा सरल एकीकरण परीक्षण है

@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

सामग्री (), बॉडी () के साथ कुछ ट्रिक्स अपनाईं लेकिन कुछ भी काम नहीं आया।


19
सलाह के रूप में, 400 स्थिति कोड को कुछ के लिए वापस नहीं किया जाना चाहिए "Username already taken"। यह एक 409 संघर्ष का अधिक होना चाहिए।
सोथिरियोस डेलिमोलिस

थैंक्स - इस परीक्षण का लक्ष्य ऐसी चीजों को निर्दिष्ट करना है।
pansanski

जवाबों:


357

सामग्री को प्राप्त करने के लिए आप 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 

7
@ TimBüthe आप स्पष्ट कर सकते हैं? एक @RestControllerइंगित करता है कि सभी हैंडलर विधियों के साथ निहित हैं @ResponseBody। इसका मतलब यह है कि स्प्रिंग HttpMessageConverterहैंडलर के रिटर्न मान को क्रमबद्ध करने के लिए और प्रतिक्रिया में लिखने के लिए इसका उपयोग करेगा । आप शरीर के साथ बहुत कुछ प्राप्त कर सकते हैं content()
सोथिरियोस डेलिमोलिस

5
@SotiriosDelimanolis सही है ... मैं अभी देख रहा हूँ JSON द्वारा लौटा है getContentAsString()जो मेरे @RestController-नोट किए गए नियंत्रक से आया है ।
पॉल

मैंने पाया कि मैं त्रुटि संदेश में क्या देख रहा था:result.getResponse().getErrorMessage()
सीटी

और रीटर्न () शून्य मान लौट रहा है
गिरिराज

@ गिरिराज andReturnवापसी के MvcResultरूप में, यहां के जावदोक में निर्दिष्ट है
सोतीरियो डेलिमोनोलिस

105

@ सोतिरियो डेलिमोनोलिस का जवाब है कि मैं इस 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"

तो यह सबूत है कि यह काम करता है!


17
बस अगर किसी के पास डायनामिक आईडी के साथ संदेश हैं, जैसे मैंने किया, तो यह जानने में मदद मिलती है कि स्ट्रिंग () विधि एक हैमरेस्ट को भी स्वीकार करती है जिसमें स्ट्रींग मैचर शामिल हैं :.andExpect(content().string(containsString("\"Username already taken");
मोलहोम

4
@ टिमबुटे, यह गलत है। यदि आपको ऐसी समस्या है, तो आपको इसे एक प्रश्न के रूप में पोस्ट करना चाहिए क्योंकि यह निश्चित रूप से अपेक्षित व्यवहार नहीं है और न ही यह व्यवहार है जिसे मैंने अपने कोड में देखा है।
पॉल

2
बस ध्यान दें कि आयात है org.hamcrest.Matchers.containsString()
मेम्बराउंड

मैंने org.hamcrest.Matchers.equalToIgnoringWhiteSpace()सभी सफेद-अंतरिक्ष वर्णों को अनदेखा करने के लिए माचिस का भी उपयोग किया । शायद यह किसी के लिए उपयोगी टिप होगा
Iwo Kucharski

66

स्प्रिंग MockMvc को अब JSON का प्रत्यक्ष समर्थन प्राप्त है। तो आप बस कहें:

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

और स्ट्रिंग तुलना के विपरीत, यह कुछ ऐसा कहेगा जैसे "लापता क्षेत्र xyz" या "संदेश अपेक्षित" ठीक है 'नोक' मिला।

इस विधि को स्प्रिंग 4.1 में पेश किया गया था।


2
क्या आप एक पूर्ण उदाहरण प्रदान कर सकते हैं? ContentRequestMatchersइस सुविधा का समर्थन करने की आवश्यकता नहीं है?
जरथुस्त्र

49

इन उत्तरों को पढ़ते हुए, मैं स्प्रिंग संस्करण 4.x से संबंधित बहुत कुछ देख सकता हूं, मैं विभिन्न कारणों से 3.2.0 संस्करण का उपयोग कर रहा हूं। तो सीधे तौर पर json समर्थन जैसी चीजें content()संभव नहीं हैं।

मैंने पाया कि उपयोग MockMvcResultMatchers.jsonPathकरना वास्तव में आसान है और उपचार का काम करता है। यहाँ एक उदाहरण एक पोस्ट विधि का परीक्षण है।

इस समाधान के साथ बोनस यह है कि आप अभी भी विशेषताओं पर मेल खा रहे हैं, पूर्ण जॉगन स्ट्रिंग तुलनाओं पर निर्भर नहीं हैं।

(उपयोग करते हुए 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));

अनुरोध निकाय सिर्फ एक जंस स्ट्रिंग था, जिसे आप आसानी से असली जौन नकली डेटा फ़ाइल से लोड कर सकते हैं, यदि आप चाहते हैं, लेकिन मैंने इसे यहां शामिल नहीं किया है क्योंकि यह प्रश्न से भटक गया होगा।

वापस लौटे वास्तविक जौन इस तरह दिखते थे:

{
    "data":"some value"
}

".andExpect (MockMvcResultMatchers.jsonPath (" $ data। डेटा ") के लिए यश। मान (अपेक्षित डेटा)"
user1697575

28

वसंत के ट्यूटोरियल से लिया गया

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संदर्भ यहाँ पाया जा सकता है


1
मैं error: incompatible types: RequestMatcher cannot be converted to ResultMatcher के लिए.andExpect(content().contentType(contentType))
इयान वॉन

@IanVaughan MockMvcResultMatchers.content ()। ContentType (contentType)
राजकुमार

23

वसंत सुरक्षा @WithMockUserऔर हैमरेस्ट का 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.")));
}

जीथब पर अधिक उदाहरण


4

यहाँ एक उदाहरण है कि JSON प्रतिक्रिया कैसे पार्स करें और यहां तक ​​कि JSON फॉर्म में सेम के साथ अनुरोध कैसे भेजें:

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

जैसा कि आप देख सकते हैं Bookकि एक अनुरोध DTO है और UpdateBookResponseJSON से प्राप्त एक प्रतिक्रिया वस्तु है। आप जेकसन के ObjectMapperविन्यास को बदलना चाह सकते हैं ।


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

यह आपको प्रतिक्रिया का शरीर देना चाहिए। आपके मामले में "उपयोगकर्ता नाम पहले से ही लिया गया है"।


विवेचना? इसकी आवश्यकता है या आप इसे इस प्रकार के उत्तर में दे सकते हैं
user1140237

2

यहाँ एक और अधिक सुंदर तरीका है

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

2

प्रतिक्रिया डेटा को स्ट्रिंग के रूप में प्राप्त करने के लिए आप 'getContentAsString' विधि का उपयोग कर सकते हैं।

    String payload = "....";
    String apiToTest = "....";

    MvcResult mvcResult = mockMvc.
                perform(post(apiToTest).
                content(payload).
                contentType(MediaType.APPLICATION_JSON)).
                andReturn();

    String responseData = mvcResult.getResponse().getContentAsString();

आप इस लिंक को परीक्षण आवेदन के लिए संदर्भित कर सकते हैं ।


1

एक संभव दृष्टिकोण केवल gsonनिर्भरता को शामिल करना है:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
</dependency>

और अपने सत्यापन करने के लिए मूल्य को पार्स करें:

@RunWith(SpringRunner.class)
@WebMvcTest(HelloController.class)
public class HelloControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private HelloService helloService;

    @Before
    public void before() {
        Mockito.when(helloService.message()).thenReturn("hello world!");
    }

    @Test
    public void testMessage() throws Exception {
        MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/"))
                .andExpect(status().isOk())
                .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON_VALUE))
                .andReturn();

        String responseBody = mvcResult.getResponse().getContentAsString();
        HelloController.ResponseDto responseDto
                = new Gson().fromJson(responseBody, HelloController.ResponseDto.class);
        Assertions.assertThat(responseDto.message).isEqualTo("hello world!");
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.