2008-09-18 16 views
51

मैं जानना चाहता हूं कि सर्वलेट के यूनिट परीक्षण करने का सबसे अच्छा तरीका क्या होगा।यूनिट परीक्षण जावा सर्वलेट

आंतरिक तरीकों का परीक्षण करना तब तक कोई समस्या नहीं है जब तक वे सर्वलेट संदर्भ का संदर्भ नहीं लेते हैं, लेकिन doGet/doPost विधियों के परीक्षण के साथ-साथ आंतरिक विधि जो संदर्भ को संदर्भित करती है या सत्र पैरामीटर का उपयोग करती है ?

क्या यह केवल यूनिवर्सिटी जैसे कि जुनीट, या अधिमानतः टेस्टएनजी का उपयोग करने का कोई तरीका है? क्या मुझे टॉमकैट सर्वर या ऐसा कुछ एम्बेड करने की ज़रूरत है?

+0

[यूनिट परीक्षण सर्वलेट्स] (के संभावित डुप्लिकेट http://stackoverflow.com/questions/53532/unit-testing- servlets) – Raedwald

उत्तर

12

HttpUnit आज़माएं, हालांकि आप 'परीक्षण परीक्षण' (एक वर्ग के) से अधिक 'एकीकरण परीक्षण' (मॉड्यूल का) स्वचालित परीक्षण लिखने की संभावना रखते हैं।

+0

ठीक है, यह यूनिट परीक्षण के बारे में वास्तव में अधिक है जैसा कि संभव हो, मैं सर्वलेट वर्ग के बीच सभी बातचीत को मोक्स के साथ बातचीत करके अन्य वर्गों के बीच बदलता हूं। – gizmo

+2

HttpUnit 2008 के बाद से कोई बदलाव नहीं हुआ है, यह सुझाव देता है कि यह एक मृत परियोजना है। – Raedwald

+3

क्या HttpUnit के लिए कोई नया प्रतिस्थापन है? – oconnor0

6

क्या आप यूनिट परीक्षणों में मैन्युअल रूप से doPost और doGet विधियों को कॉल कर रहे हैं? यदि ऐसा है तो आप नकली वस्तुओं को प्रदान करने के लिए HttpServletRequest विधियों को ओवरराइड कर सकते हैं।

myServlet.doGet(new HttpServletRequestWrapper() { 
    public HttpSession getSession() { 
     return mockSession; 
    } 

    ... 
} 

HttpServletRequestWrapper सुविधा जावा क्लास है। मैं तुम्हें नकली HTTP अनुरोध बनाने के लिए अपने इकाई परीक्षण में एक उपयोगिता विधि बनाने के लिए सुझाव देते हैं:

public void testSomething() { 
    myServlet.doGet(createMockRequest(), createMockResponse()); 
} 

protected HttpServletRequest createMockRequest() { 
    HttpServletRequest request = new HttpServletRequestWrapper() { 
     //overrided methods 
    } 
} 

यह एक आधार सर्वलेट सुपर क्लास में नकली निर्माण तरीकों रख दिया और यह विस्तार करने के लिए सभी सर्वलेट्स इकाई परीक्षण बनाने के लिए भी बेहतर है।

+3

HttpServletRequestWrapper में डिफ़ॉल्ट कन्स्ट्रक्टर नहीं है, केवल एक HttpServletRequest पैरामीटर वाला है। –

43

अधिकांश समय मैं शुद्ध यूनिट टेस्ट की बजाय 'इंटीग्रेशन टेस्ट' के माध्यम से सर्वलेट्स और जेएसपी का परीक्षण करता हूं। (उच्च

  • HttpUnit (सबसे पुराना और सबसे अच्छा जाना जाता है, बहुत कम स्तर है जो अच्छा है या अपनी आवश्यकताओं पर निर्भर करता है बुरा हो सकता है)
  • HtmlUnit:/TestNG उपलब्ध सहित JUnit के लिए ऐड-ऑन की एक बड़ी संख्या में हैं HttpUnit से स्तर है, जो कई परियोजनाओं के लिए बेहतर)
  • JWebUnit (अन्य परीक्षण उपकरण के शीर्ष पर बैठता है और उन्हें सरल बनाने की कोशिश करता है - एक मैं पसंद करते हैं)
  • WatiJ और सेलेनियम (अपने ब्राउज़र का उपयोग परीक्षण, ऐसा करने के लिए जो अधिक हेवीवेट लेकिन यथार्थवादी है)

यह एक साधारण ऑर्डर प्रोसेसिंग सर्वलेट के लिए जेडब्लूबिट परीक्षण है जो 'orderEntry.html' फ़ॉर्म से इनपुट को संसाधित करता है।

public class OrdersPageTest { 
    private static final String WEBSITE_URL = "http://localhost:8080/demo1"; 

    @Before 
    public void start() { 
     webTester = new WebTester(); 
     webTester.setTestingEngineKey(TestingEngineRegistry.TESTING_ENGINE_HTMLUNIT); 
     webTester.getTestContext().setBaseUrl(WEBSITE_URL); 
    } 
    @Test 
    public void sanity() throws Exception { 
     webTester.beginAt("/orderEntry.html"); 
     webTester.assertTitleEquals("Order Entry Form"); 
    } 
    @Test 
    public void idIsRequired() throws Exception { 
     webTester.beginAt("/orderEntry.html"); 
     webTester.submit(); 
     webTester.assertTextPresent("ID Missing!"); 
    } 
    @Test 
    public void nameIsRequired() throws Exception { 
     webTester.beginAt("/orderEntry.html"); 
     webTester.setTextField("id","AB12"); 
     webTester.submit(); 
     webTester.assertTextPresent("Name Missing!"); 
    } 
    @Test 
    public void validOrderSucceeds() throws Exception { 
     webTester.beginAt("/orderEntry.html"); 
     webTester.setTextField("id","AB12"); 
     webTester.setTextField("name","Joe Bloggs"); 

     //fill in order line one 
     webTester.setTextField("lineOneItemNumber", "AA"); 
     webTester.setTextField("lineOneQuantity", "12"); 
     webTester.setTextField("lineOneUnitPrice", "3.4"); 

     //fill in order line two 
     webTester.setTextField("lineTwoItemNumber", "BB"); 
     webTester.setTextField("lineTwoQuantity", "14"); 
     webTester.setTextField("lineTwoUnitPrice", "5.6"); 

     webTester.submit(); 
     webTester.assertTextPresent("Total: 119.20"); 
    } 
    private WebTester webTester; 
} 
6

Mockrunner (http://mockrunner.sourceforge.net/index.html) ऐसा कर सकते हैं: यह एक ग्राहक आईडी, ग्राहक का नाम और एक या अधिक आदेश आइटम की उम्मीद है। यह एक नकली जे 2 ईई कंटेनर प्रदान करता है जिसका उपयोग Servlets का परीक्षण करने के लिए किया जा सकता है। इसका उपयोग यूनिट परीक्षण के लिए अन्य सर्वर-साइड कोड जैसे ईजेबी, जेडीबीसी, जेएमएस, स्ट्रैट्स के लिए भी किया जा सकता है। मैंने केवल जेडीबीसी और ईजेबी क्षमताओं का उपयोग किया है।

+2

mockrunner को 200 9 से अपडेट नहीं किया गया है। क्या कोई विकल्प बनाए रखा जा रहा है? – datguy

10

मैंने पोस्ट किए गए उत्तरों को देखा और सोचा कि मैं एक और पूरा समाधान पोस्ट करूंगा जो वास्तव में एम्बेडेड ग्लासफ़िश और उसके अपाचे मैवेन प्लगइन का उपयोग करके परीक्षण कैसे करें।

मैं अपने ब्लॉग Using GlassFish 3.1.1 Embedded with JUnit 4.x and HtmlUnit 2.x पर पूरा प्रक्रिया में तेजी लिखा था और यहाँ Bitbucket पर डाउनलोड के लिए पूरा परियोजना रखा: image-servlet

मैं JSP/JSF टैग के लिए एक छवि सर्वलेट पर एक और पोस्ट में बस से पहले मैं इस देखा देख रहा था सवाल।इसलिए मैंने इस पोस्ट के लिए एक पूर्ण इकाई परीक्षण संस्करण के साथ दूसरे पोस्ट से उपयोग किए गए समाधान को जोड़ा।

कैसे टेस्ट

अपाचे Maven एक अच्छी तरह से परिभाषित जीवन चक्र कि test भी शामिल है। मैं अपने समाधान को लागू करने के लिए integration-test नामक एक और जीवन चक्र के साथ इसका उपयोग करूंगा।

  1. surefire प्लगइन में मानक जीवन चक्र इकाई परीक्षण अक्षम करें।
  2. surefire-plugin
  3. के निष्पादन के हिस्से के रूप में integration-test जोड़ें पीओएम में ग्लासफ़िश मेवेन प्लगइन जोड़ें।
  4. integration-test जीवन चक्र के दौरान निष्पादित करने के लिए ग्लासफ़िश कॉन्फ़िगर करें।
  5. रन यूनिट परीक्षण (एकीकरण परीक्षण)।

ग्लासफिश प्लगइन

<build> के हिस्से के रूप इस प्लगइन जोड़ें।

 <plugin> 
      <groupId>org.glassfish</groupId> 
      <artifactId>maven-embedded-glassfish-plugin</artifactId> 
      <version>3.1.1</version> 
      <configuration> 
       <!-- This sets the path to use the war file we have built in the target directory --> 
       <app>target/${project.build.finalName}</app> 
       <port>8080</port> 
       <!-- This sets the context root, e.g. http://localhost:8080/test/ --> 
       <contextRoot>test</contextRoot> 
       <!-- This deletes the temporary files during GlassFish shutdown. --> 
       <autoDelete>true</autoDelete> 
      </configuration> 
      <executions> 
       <execution> 
        <id>start</id> 
        <!-- We implement the integration testing by setting up our GlassFish instance to start and deploy our application. --> 
        <phase>pre-integration-test</phase> 
        <goals> 
         <goal>start</goal> 
         <goal>deploy</goal> 
        </goals> 
       </execution> 
       <execution> 
        <id>stop</id> 
        <!-- After integration testing we undeploy the application and shutdown GlassFish gracefully. --> 
        <phase>post-integration-test</phase> 
        <goals> 
         <goal>undeploy</goal> 
         <goal>stop</goal> 
        </goals> 
       </execution> 
      </executions> 
     </plugin> 

अचूक प्लगइन

जोड़ें/<build> के हिस्से के रूप प्लगइन को संशोधित।

 <plugin> 
      <groupId>org.apache.maven.plugins</groupId> 
      <artifactId>maven-surefire-plugin</artifactId> 
      <version>2.12.4</version> 
      <!-- We are skipping the default test lifecycle and will test later during integration-test --> 
      <configuration> 
       <skip>true</skip> 
      </configuration> 
      <executions> 
       <execution> 
        <phase>integration-test</phase> 
        <goals> 
         <!-- During the integration test we will execute surefire:test --> 
         <goal>test</goal> 
        </goals> 
        <configuration> 
         <!-- This enables the tests which were disabled previously. --> 
         <skip>false</skip> 
        </configuration> 
       </execution> 
      </executions> 
     </plugin> 

HTMLUnit

नीचे दिए गए उदाहरण की तरह एकीकरण परीक्षणों जोड़ें।

@Test 
public void badRequest() throws IOException { 
    webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); 
    webClient.getOptions().setPrintContentOnFailingStatusCode(false); 
    final HtmlPage page = webClient.getPage("http://localhost:8080/test/images/"); 
    final WebResponse response = page.getWebResponse(); 
    assertEquals(400, response.getStatusCode()); 
    assertEquals("An image name is required.", response.getStatusMessage()); 
    webClient.getOptions().setThrowExceptionOnFailingStatusCode(true); 
    webClient.getOptions().setPrintContentOnFailingStatusCode(true); 
    webClient.closeAllWindows(); 
} 

मैं अपने ब्लॉग Using GlassFish 3.1.1 Embedded with JUnit 4.x and HtmlUnit 2.x पर पूरा प्रक्रिया में तेजी लिखा था और यहाँ Bitbucket पर डाउनलोड के लिए पूरा परियोजना रखा: image-servlet

आप कोई प्रश्न हैं, एक टिप्पणी छोड़ कृपया। मुझे लगता है कि यह आपके लिए सर्वलेट के लिए योजना बना रहे किसी भी परीक्षण के आधार के रूप में उपयोग करने के लिए एक संपूर्ण उदाहरण है।

0

अपडेट किया गया फरवरी 2018: OpenBrace Limited has closed down, और इसका Obmimic उत्पाद अब समर्थित नहीं है।

एक और समाधान मेरी ObMimic लाइब्रेरी का उपयोग करना है, जो विशेष रूप से सर्वलेट्स के यूनिट परीक्षण के लिए डिज़ाइन किया गया है। यह सभी सर्वलेट एपीआई कक्षाओं के पूर्ण सादे-जावा कार्यान्वयन प्रदान करता है, और आप अपने परीक्षणों के लिए आवश्यकतानुसार इन्हें कॉन्फ़िगर और निरीक्षण कर सकते हैं।

आप वास्तव में इसे जुइनिट या टेस्टएनजी परीक्षणों से डूगेट/डूपोस्ट विधियों को कॉल करने के लिए उपयोग कर सकते हैं, और किसी भी आंतरिक तरीकों का परीक्षण करने के लिए भी भले ही वे ServletContext का संदर्भ लें या सत्र पैरामीटर (या किसी अन्य Servlet API सुविधाओं) का उपयोग करें।

इसे बाहरी या एम्बेडेड कंटेनर की आवश्यकता नहीं है, जो आपको व्यापक HTTP-आधारित "एकीकरण" परीक्षणों तक सीमित नहीं करता है, और सामान्य उद्देश्य वाले मैक्स के विपरीत इसमें पूर्ण सर्वलेट एपीआई व्यवहार "बेक्ड इन" है, इसलिए आपका परीक्षण "स्थिति" के आधार पर "स्थिति" आधारित हो सकते हैं (उदाहरण के लिए आपके परीक्षणों को आपके कोड द्वारा किए गए सर्वलेट एपीआई कॉल के सटीक अनुक्रम पर भरोसा नहीं करना चाहिए, न ही Servlet API का जवाब देने की आपकी अपेक्षाओं पर निर्भर होना चाहिए प्रत्येक कॉल के लिए)।

How to test my servlet using JUnit पर मेरे उत्तर में एक साधारण उदाहरण है।पूर्ण विवरण और मुफ्त डाउनलोड के लिए ObMimic वेबसाइट देखें।

+0

"Obmimic स्थापित करने के लिए: Obmimic-1.1.000.zip संग्रह को उस स्थान पर अनजिप करें जहां ..." रुको, क्या ?! – Innokenty

3

सर्वलेट doPost के लिए एक JUnit परीक्षण के इस कार्यान्वयन() विधि HttpRequest, HttpResponse, HttpSession, ServletResponse और RequestDispatcher के उदाहरण ऊपर मजाक के लिए केवल Mockito पुस्तकालय पर निर्भर करता है। पैरामीटर कुंजी और जावाबीन इंस्टेंस को उन लोगों के साथ बदलें जो संबंधित जेएसपी फ़ाइल में संदर्भित मानों से मेल खाते हैं, जिससे doPost() कहा जाता है।

Mockito Maven निर्भरता:

<dependency> 
     <groupId>org.mockito</groupId> 
     <artifactId>mockito-all</artifactId> 
     <version>1.9.5</version> 
</dependency> 

JUnit परीक्षण:

import javax.servlet.RequestDispatcher; 
import javax.servlet.ServletContext; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.servlet.http.HttpSession; 

import java.io.IOException; 

import static org.junit.Assert.assertFalse; 
import static org.junit.Assert.assertTrue; 
import static org.mockito.Mockito.*; 

/** 
* Unit tests for the {@code StockSearchServlet} class. 
* @author Bob Basmaji 
*/ 
public class StockSearchServletTest extends HttpServlet { 
    // private fields of this class 
    private static HttpServletRequest request; 
    private static HttpServletResponse response; 
    private static StockSearchServlet servlet; 
    private static final String SYMBOL_PARAMETER_KEY = "symbol"; 
    private static final String STARTRANGE_PARAMETER_KEY = "startRange"; 
    private static final String ENDRANGE_PARAMETER_KEY = "endRange"; 
    private static final String INTERVAL_PARAMETER_KEY = "interval"; 
    private static final String SERVICETYPE_PARAMETER_KEY = "serviceType"; 

    /** 
    * Sets up the logic common to each test in this class 
    */ 
    @Before 
    public final void setUp() { 
     request = mock(HttpServletRequest.class); 
     response = mock(HttpServletResponse.class); 

     when(request.getParameter("symbol")) 
       .thenReturn("AAPL"); 

     when(request.getParameter("startRange")) 
       .thenReturn("2016-04-23 00:00:00"); 

     when(request.getParameter("endRange")) 
       .thenReturn("2016-07-23 00:00:00"); 

     when(request.getParameter("interval")) 
       .thenReturn("DAY"); 

     when(request.getParameter("serviceType")) 
       .thenReturn("WEB"); 

     String symbol = request.getParameter(SYMBOL_PARAMETER_KEY); 
     String startRange = request.getParameter(STARTRANGE_PARAMETER_KEY); 
     String endRange = request.getParameter(ENDRANGE_PARAMETER_KEY); 
     String interval = request.getParameter(INTERVAL_PARAMETER_KEY); 
     String serviceType = request.getParameter(SERVICETYPE_PARAMETER_KEY); 

     HttpSession session = mock(HttpSession.class); 
     when(request.getSession()).thenReturn(session); 
     final ServletContext servletContext = mock(ServletContext.class); 
     RequestDispatcher dispatcher = mock(RequestDispatcher.class); 
     when(servletContext.getRequestDispatcher("/stocksearchResults.jsp")).thenReturn(dispatcher); 
     servlet = new StockSearchServlet() { 
      public ServletContext getServletContext() { 
       return servletContext; // return the mock 
      } 
     }; 

     StockSearchBean search = new StockSearchBean(symbol, startRange, endRange, interval); 
     try { 
      switch (serviceType) { 
       case ("BASIC"): 
        search.processData(ServiceType.BASIC); 
        break; 
       case ("DATABASE"): 
        search.processData(ServiceType.DATABASE); 
        break; 
       case ("WEB"): 
        search.processData(ServiceType.WEB); 
        break; 
       default: 
        search.processData(ServiceType.WEB); 
      } 
     } catch (StockServiceException e) { 
      throw new RuntimeException(e.getMessage()); 
     } 
     session.setAttribute("search", search); 
    } 

    /** 
    * Verifies that the doPost method throws an exception when passed null arguments 
    * @throws ServletException 
    * @throws IOException 
    */ 
    @Test(expected = NullPointerException.class) 
    public final void testDoPostPositive() throws ServletException, IOException { 
     servlet.doPost(null, null); 
    } 

    /** 
    * Verifies that the doPost method runs without exception 
    * @throws ServletException 
    * @throws IOException 
    */ 
    @Test 
    public final void testDoPostNegative() throws ServletException, IOException { 
     boolean throwsException = false; 
     try { 
      servlet.doPost(request, response); 
     } catch (Exception e) { 
      throwsException = true; 
     } 
     assertFalse("doPost throws an exception", throwsException); 
    } 
} 
+0

'सत्यापित (सत्र) .setAttribute (" फ़ील्ड "," मान ") 'संभवतः एक अच्छा दावा भी है। – Mahdi

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