2012-02-23 14 views
28

मैं एक विधि है जो निम्न पंक्ति है के लिए एक इकाई परीक्षण लिख रहा हूँ करने के लिए निर्भर परीक्षण:यूनिट एक विधि अनुरोध संदर्भ

String sessionId = RequestContextHolder.currentRequestAttributes().getSessionId(); 

मैं निम्नलिखित त्रुटि मिलती है:

java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

कारण काफी स्पष्ट है - मैं अनुरोध संदर्भ में परीक्षण नहीं चला रहा हूं।

सवाल यह है कि, मैं एक ऐसे परीक्षण का परीक्षण कैसे कर सकता हूं जिसमें परीक्षण वातावरण में अनुरोध संदर्भ पर निर्भर विधि में कॉल शामिल हो?

बहुत बहुत धन्यवाद।

उत्तर

30

आप अपनी इच्छाओं को वापस करने से पहले RequestAttributes ऑब्जेक्ट को मॉक/स्टब कर सकते हैं और फिर अपने परीक्षण शुरू करने से पहले RequestContextHolder.setRequestAttributes(RequestAttributes) पर अपने नकली/स्टब के साथ कॉल कर सकते हैं।

class ClassToTest { 
    public void doSomething() { 
     String sessionId = RequestContextHolder.currentRequestAttributes().getSessionId(); 
     // Do something with sessionId 
    } 
} 

आप वर्ग RequestContextHolder का उपयोग करता है को बदलने की क्षमता नहीं है, तो आप RequestContextHolder वर्ग अपने परीक्षण कोड में रद्द कर सकते थे:

@Mock 
private RequestAttributes attrs; 

@Before 
public void before() { 
    MockitoAnnotations.initMocks(this); 
    RequestContextHolder.setRequestAttributes(attrs); 

    // do you when's on attrs 
} 

@Test 
public void testIt() { 
    // do your test... 
} 
+1

धन्यवाद @ निकोलस.hauschild। सही और साफ समाधान! – satoshi

+0

@ निकोलस, त्वरित समाधान के लिए धन्यवाद, यह मेरे लिए काम करता है, धन्यवाद एक बार फिर – Bravo

1

अपने वर्ग मानते हुए की तरह कुछ है। आईई। आप एक ही पैकेज के साथ एक ही पैकेज में एक ही पैकेज बनाते हैं, और यह सुनिश्चित करते हैं कि यह वास्तविक स्प्रिंग क्लास से पहले लोड हो।

package org.springframework.web.context.request; 

public class RequestContextHolder { 
    static RequestAttributes currentRequestAttributes() { 
     return new MyRequestAttributes(); 
    } 

    static class MyRequestAttributes implements RequestAttributes { 
     public String getSessionId() { 
      return "stub session id"; 
     } 
     // Stub out the other methods. 
    } 
} 

अब, जब आपके परीक्षण चला, वे अपने RequestContextHolder वर्ग लेने और वसंत एक (classpath ऐसा करने के लिए सेट किया गया है यह सोचते हैं) करने के लिए उपयोग है कि वरीयता में होगा। यह आपके परीक्षणों को चलाने के लिए एक विशेष अच्छा तरीका नहीं है, लेकिन यदि आप जिस कक्षा में परीक्षण कर रहे हैं उसे बदल नहीं सकते हैं तो यह आवश्यक हो सकता है।

वैकल्पिक रूप से, आप एक अमूर्तता के पीछे सत्र आईडी पुनर्प्राप्ति छुपा सकते हैं।

public interface SessionIdAccessor { 
    public String getSessionId(); 
} 

एक कार्यान्वयन बनाएँ::

public class RequestContextHolderSessionIdAccessor implements SessionIdAccessor { 
    public String getSessionId() { 
     return RequestContextHolder.currentRequestAttributes().getSessionId(); 
    } 
} 

और अपनी कक्षा में अमूर्त का उपयोग करें:

class ClassToTest { 
    SessionIdAccessor sessionIdAccessor; 

    public ClassToTest(SessionIdAccessor sessionIdAccessor) { 
     this.sessionIdAccessor = sessionIdAccessor; 
    } 

    public void doSomething() { 
     String sessionId = sessionIdAccessor.getSessionId(); 
     // Do something with sessionId 
    } 
} 

तो फिर आप अपने परीक्षण के लिए एक डमी कार्यान्वयन प्रदान कर सकते हैं उदाहरण के लिए एक इंटरफेस का परिचय:

public class DummySessionIdAccessor implements SessionIdAccessor { 
    public String getSessionId() { 
     return "dummy session id"; 
    } 
} 

इस तरह की चीज अमूर्तताओं के पीछे कुछ पर्यावरणीय विवरण छिपाने के लिए एक सामान्य सर्वोत्तम अभ्यास को हाइलाइट करती है ताकि यदि आपका पर्यावरण बदलता है तो आप उन्हें स्वैप कर सकते हैं। यह 'असली' वाले लोगों के लिए डमी कार्यान्वयन को स्वैप करके अपने परीक्षणों को कम भंगुर बनाने के लिए समान रूप से लागू होता है।

+0

धन्यवाद, @PaulGrime। दूसरा समाधान वह है जिसे मैंने माना था, लेकिन मैं एक ऐसे समाधान की तलाश में था जहां मुझे अपना मुख्य कोड बदलने की ज़रूरत नहीं थी ... अगर कोई दूसरा बेहतर समाधान सुझाता है तो मैं इस समाधान का उपयोग करूंगा! – satoshi

1

विधि युक्त हैं:

String sessionId = RequestContextHolder.currentRequestAttributes().getSessionId(); 

, वेब नियंत्रक तरीका है तो मैं विधि हस्ताक्षर बदलने के लिए सिफारिश करेंगे, ताकि आप/वसंत विधि करने के लिए एक अलग paremter के रूप में अनुरोध गुजरती हैं।

फिर आप समस्याग्रस्त भाग स्ट्रिंग RequestContextHolder.currentRequestAttributes() को हटा सकते हैं और HttpSession का उपयोग कर सकते हैं।

फिर परीक्षण में एक मॉक सत्र (MockHttpSession) ऑब्जेक्ट का उपयोग करना बहुत आसान होना चाहिए।

@RequestMapping... 
public ModelAndView(... HttpSession session) { 
    String id = session.getId(); 
    ... 
} 
93

स्प्रिंग-टेस्ट में एक लचीला अनुरोध मॉक है जिसे मॉकहट्स्सर्वलेटरक्वैस्ट कहा जाता है।

MockHttpServletRequest request = new MockHttpServletRequest(); 
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); 
+3

यह स्वीकार्य उत्तर होना चाहिए! – Eugene

+2

@Eugene से सहमत हैं। –

+0

आपको उपरोक्त के लिए javax.servlet: javax.servlet-api पर एक स्पष्ट निर्भरता जोड़ने की आवश्यकता हो सकती है (स्प्रिंग 5 उसमें खींच नहीं लेता है) – djb

संबंधित मुद्दे