2013-07-17 6 views
9

मैं एक लंबे समय से चल बैकएंड प्रक्रिया शुरू करने के लिए (यह एक क्रोन शेड्यूल पर सामान्य रूप से है, लेकिन हम इसे मैन्युअल रूप से शुरू की क्षमता चाहते हैं) एक शोकहारा यूआरएल उपयोग कर रहा हूँ।परीक्षण स्प्रिंग asyncResult() और jsonPath() एक साथ

नीचे दिया गया कोड काम करता है और जब मैं मैन्युअल रूप से परीक्षण करता हूं तो मुझे ब्राउज़र में परिणाम दिखाई देता है।

@ResponseBody 
@RequestMapping(value = "/trigger/{jobName}", method = RequestMethod.GET) 
public Callable<TriggerResult> triggerJob(@PathVariable final String jobName) { 

    return new Callable<TriggerResult>() { 
     @Override 
     public TriggerResult call() throws Exception { 
      // Code goes here to locate relevant job and kick it off, waiting for result 
      String message = <result from my job>; 
      return new TriggerResult(SUCCESS, message); 
     } 
    }; 
} 

जब मैं Callable के बिना इस परीक्षण मैं नीचे दिए गए कोड का इस्तेमाल किया और यह सब काम करता है (मैं पद को आसान बनाने की उम्मीद त्रुटि संदेश परिवर्तित)।

mockMvc.perform(get("/trigger/job/xyz")) 
    .andExpect(status().isOk()) 
    .andDo(print()) 
    .andExpect(jsonPath("status").value("SUCCESS")) 
    .andExpect(jsonPath("message").value("A meaningful message appears")); 

जब मैंने Callable जोड़ा, हालांकि यह काम नहीं करता है। मैंने नीचे भी कोशिश की लेकिन यह काम नहीं किया। किसी और को सफलता मिली?

mockMvc.perform(get("/trigger/job/xyz")) 
    .andExpect(status().isOk()) 
    .andDo(print()) 
    .andExpect(request().asyncResult(jsonPath("status").value("SUCCESS"))) 
    .andExpect(request().asyncResult(jsonPath("message").value("A meaningful message appears"))); 

नीचे मेरे प्रिंट() से प्रासंगिक हिस्सा है। ऐसा लगता है कि mockMvc इस मामले में जेसन को सही तरीके से उलझा नहीं सकता है (भले ही यह मेरे ब्राउज़र में काम करता हो)? जब मैं Callable के बिना ऐसा करता हूं तो मुझे पूर्ण JSON दिखाई देता है।

MockHttpServletRequest: 
    HTTP Method = GET 
    Request URI = /trigger/job/xyz 
     Parameters = {} 
     Headers = {} 

     Handler: 
      Type = foo.bar.web.controller.TriggerJobController 
      Method = public java.util.concurrent.Callable<foo.bar.myproject.web.model.TriggerResult> foo.bar.myproject.web.controller.TriggerJobController.triggerJob(java.lang.String) 

      Async: 
Was async started = true 
     Async result = [email protected] 


Resolved Exception: 
      Type = null 

    ModelAndView: 
     View name = null 
      View = null 
      Model = null 

     FlashMap: 

MockHttpServletResponse: 
      Status = 200 
    Error message = null 
     Headers = {} 
    Content type = null 
      Body = 
    Forwarded URL = null 
    Redirected URL = null 
     Cookies = [] 

उत्तर

16

बड के जवाब में वास्तव में सही दिशा में मुझे बिंदु मदद की लेकिन यह काफी काम नहीं किया था, क्योंकि यह async परिणाम के लिए इंतजार नहीं किया। इस प्रश्न को पोस्ट करने के बाद, वसंत-एमवीसी-शोकेस नमूने (https://github.com/SpringSource/spring-mvc-showcase) अपडेट कर दिए गए हैं।

जब आप एमवीसीआरसल्ट को पुनर्प्राप्त करते हैं तो कॉल के पहले भाग में ऐसा लगता है, आपको एसिंक्रसल्ट() पर जोर देना होगा और JSON pojo मैपिंग के मामले में आपको वास्तविक प्रकार पर जोर देना होगा (JSON नहीं) । तो मुझे नीचे तीसरी पंक्ति को बड के उत्तर में जोड़ने की ज़रूरत थी, फिर बाकी बस काम करता है।

MvcResult mvcResult = this.mockMvc.perform(get("/trigger/job/xyz")) 
    .andExpect(request().asyncStarted()) 
    .andExpect(request().asyncResult(instanceOf(TriggerResult.class))) 
    .andReturn(); 

this.mockMvc.perform(asyncDispatch(mvcResult)) 
    .andExpect(status().isOk()) 
    .andExpect(content().contentType(MediaType.APPLICATION_JSON)) 
    .andExpect(jsonPath("status").value("SUCCESS")) 
    .andExpect(jsonPath("message").value("A meaningful message appears")); 

नोट:instanceOf()org.hamcrest.CoreMatchers.instanceOf है। हैमक्रिस्ट पुस्तकालयों तक पहुंच प्राप्त करने के लिए नवीनतम hamcrest-library जार शामिल हैं।

Maven के लिए ...

<dependency> 
     <groupId>org.hamcrest</groupId> 
     <artifactId>hamcrest-library</artifactId> 
     <version>LATEST VERSION HERE</version> 
     <scope>test</scope> 
    </dependency> 
+0

यह इंगित करना अच्छा होगा कि विधि 'instanceOf() 'हैमक्रिस्ट लाइब्रेरी का हिस्सा है। इसे खोजने के लिए मुझे थोड़ी देर लग गई और फिर उचित ** मेवेन ** आयात डाला। इस [एमवीसी शोकेस उदाहरण] पर एक नज़र डालें (https://github.com/spring-projects/spring-mvc-showcase/blob/master/src/test/java/org/springframework/samples/mvc/async/CallableControllerTests .java) मदद की। –

+0

निश्चित, अच्छा बिंदु। जोड़ा गया। –

+0

asyncDispatch() पूरी तरह से आवश्यक उपयोग कर रहा है? ऐसा लगता है कि परीक्षण के encapsulation तोड़ने के लिए लगता है - जो सिर्फ यह पता होना चाहिए कि जब यह एक जीईटी/ट्रिगर/नौकरी/xyz को जीईटी भेजता है - यह जानने के लिए कि उस नियंत्रक के कार्यान्वयन async –

5

मुझे लगता है कि आप शुरू कर दिया Async के परिणाम पर asyncDispatch उपयोग करना चाहते हैं कॉल नीचे

http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.html

प्रयोग लिंक से संदर्भ कोड पहले एक अनुरोध प्रदर्शन करना शामिल है कि async प्रसंस्करण शुरू होता है:

MvcResult mvcResult = this.mockMvc.perform(get("/trigger/job/xyz")) 
     .andExpect(request().asyncStarted()) 
     .andReturn(); 

और उसके बाद एमवीसीआरसल्ट का उपयोग कर एसिंक प्रेषण निष्पादित करना:

this.mockMvc.perform(asyncDispatch(mvcResult)) 
     .andExpect(status().isOk()) 
     .andExpect(content().contentType(MediaType.APPLICATION_JSON)) 
     .andExpect(content().string(.......)); 

या अपने मामले

this.mockMvc.perform(asyncDispatch(mvcResult)) 
     .andExpect(status().isOk()) 
     .andExpect(content().contentType(MediaType.APPLICATION_JSON)) 
     .andExpect(jsonPath("status").value("SUCCESS")) 
     .andExpect(jsonPath("message").value("A meaningful message appears")); 
+0

बहुत बढ़िया! बहुत बहुत धन्यवाद। मुझे दस्तावेज़ों में यह नहीं मिला और यह वही था जो मैं बाद में था। –

+0

हमम ... ऐसा लगता है कि यह वास्तव में अजीब है और प्रतीक्षा नहीं कर रहा है क्योंकि परीक्षण यादृच्छिक रूप से विफल रहता है। –

5

मैट जवाब सही है, लेकिन मैं perform बस काम करना चाहते हैं। नीचे एक प्रदर्शन विधि है जिसका उपयोग आप एसिंक और सिंक अनुरोध दोनों का परीक्षण करने के लिए कर सकते हैं। तो आपको अपने परीक्षणों में देखभाल करने की आवश्यकता नहीं है कि बैकएंड अनुरोधों को कैसे प्रबंधित करता है। आप वैसे भी वास्तविक प्रतिक्रिया की रुचि रखते हैं, है ना?तब आधार वर्ग का विस्तार करके अपने परीक्षण को लागू

import static org.hamcrest.Matchers.anything; 
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; 
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request; 
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; 

@WebAppConfiguration 
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml") 
public abstract class AbstractMockMvcTests { 

    @Autowired 
    protected WebApplicationContext wac; 

    private MockMvc mockMvc; 

    @Before 
    public void setup() throws Exception { 
    mockMvc = webAppContextSetup(this.wac).build(); 
    } 

    protected ResultActions perform(MockHttpServletRequestBuilder builder) throws Exception { 
    ResultActions resultActions = mockMvc.perform(builder); 
    if (resultActions.andReturn().getRequest().isAsyncStarted()) { 
     return mockMvc.perform(asyncDispatch(resultActions 
      .andExpect(request().asyncResult(anything())) 
      .andReturn())); 
    } else { 
     return resultActions; 
    } 
    } 
} 

:

ResultActions perform(MockHttpServletRequestBuilder builder) throws Exception { 
    ResultActions resultActions = mockMvc.perform(builder); 
    if (resultActions.andReturn().getRequest().isAsyncStarted()) { 
     return mockMvc.perform(asyncDispatch(resultActions 
      .andExpect(request().asyncResult(anything())) 
      .andReturn())); 
    } else { 
     return resultActions; 
    } 
} 

एक तरह से अपने परीक्षण के लिए है कि एकीकृत करने के लिए एक आम सार आधार वर्ग में रख और इससे अपनी वास्तविक परीक्षा कक्षाओं का विस्तार करने के लिए है और प्रदर्शन विधि का उपयोग करें। इस उदाहरण में mockMvc को कस्टम प्रदर्शन विधि का उपयोग करने के लिए सभी भावी परीक्षण लेखकों को धीरे-धीरे मार्गदर्शन करने के लिए निजी बनाया गया है।

@RunWith(SpringJUnit4ClassRunner.class) 
public class CallableControllerTests extends AbstractMockMvcTests { 

    @Test 
    public void responseBodyAsync() throws Exception { 
    perform(get("/async/callable/response-body")) 
     .andExpect(status().isOk()) 
     .andExpect(content().contentType("text/plain;charset=ISO-8859-1")) 
     .andExpect(content().string("Callable result")); 
    } 

    @Test 
    public void responseBodySync() throws Exception { 
    perform(get("/sync/foobar/response-body")) 
     .andExpect(status().isOk()) 
     .andExpect(content().contentType("text/plain;charset=ISO-8859-1")) 
     .andExpect(content().string("Sync result")); 
    } 
} 
संबंधित मुद्दे