سؤال

أود أن أعرف ما يمكن أن يكون أفضل طريقة للقيام اختبار وحدة من بريمج.

اختبار الطرق الداخلية ليست مشكلة طالما أنها لا تشير إلى بريمج السياق ، ولكن ماذا عن اختبار doGet/doPost أساليب فضلا عن الأسلوب الداخلية التي تشير إلى سياق أو الاستفادة من الدورة المعلمات ؟

هل هناك طريقة للقيام بذلك ببساطة عن طريق استخدام الأدوات الكلاسيكية مثل JUnit ، أو ويفضل TestNG?هل أنا بحاجة إلى تضمين خادم قط أو شيئا كهذا ؟

هل كانت مفيدة؟

المحلول

محاولة HttpUnit, ، على الرغم من أن أنت من المحتمل أن ينتهي في كتابة الاختبارات التلقائية التي هي أكثر 'اختبارات التكامل' (وحدة) من 'وحدة الاختبارات' (من فئة واحدة).

نصائح أخرى

معظم الوقت أنا اختبار سيرفلتس و JSP طريق التكامل الاختبارات' بدلا من محض وحدة الاختبارات.هناك عدد كبير من إضافات JUnit/TestNG المتاحة بما في ذلك:

  • HttpUnit (أقدم أفضل ما يعرف ، على مستوى منخفض جدا والتي يمكن أن تكون جيدة أو سيئة اعتمادا على الاحتياجات الخاصة بك)
  • HtmlUnit (أعلى مستوى من HttpUnit الذي هو أفضل بالنسبة للعديد من المشاريع)
  • JWebUnit (يجلس على أعلى من غيرها من أدوات الاختبار و يحاول تبسيط منهم - واحد كنت تفضل ذلك)
  • WatiJ و السيلينيوم (استخدام المتصفح للقيام اختبار, الذي هو أكثر من الوزن الثقيل ولكن واقعية)

هذا هو JWebUnit اختبار بسيط تجهيز النظام بريمج الذي عمليات الإدخال من شكل '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;
}

نظرت إلى نشر إجابات فكرت في أن ما بعد حل أكثر اكتمالا أن الواقع يوضح كيفية القيام اختبار باستخدام جزءا لا يتجزأ من GlassFish و أباتشي مخضرم المساعد.

كتبت العملية الكاملة على بلدي بلوق باستخدام GlassFish 3.1.1 جزءا لا يتجزأ مع JUnit 4.x و HtmlUnit 2.x و وضع المشروع كاملة للتحميل على Bitbucket هنا: صورة-بريمج

كنت أبحث عن وظيفة أخرى في صورة بريمج عن JSP/JSF الكلمات فقط قبل أن أرى هذا السؤال.لذا جنبا إلى جنب الحل اعتدت من الآخر بعد مع وحدة كاملة إصدار اختبار هذا المنصب.

كيفية اختبار

أباتشي مخضرم لديه واضحة المعالم التي تشمل دورة حياة test.وسوف تستخدم هذه جنبا إلى جنب مع آخر دورة حياة تسمى integration-test لتنفيذ الحل.

  1. تعطيل القياسية دورة حياة وحدة اختبار في مؤكدة المساعد.
  2. إضافة integration-test كجزء من الإعدام مؤكدة-المساعد
  3. إضافة GlassFish مخضرم المساعد بوم.
  4. تكوين GlassFish لتنفيذ أثناء integration-test دورة الحياة.
  5. تشغيل وحدة الاختبارات (اختبارات التكامل).

GlassFish المساعد

إضافة هذا البرنامج المساعد كجزء من <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();
}

كتبت العملية الكاملة على بلدي بلوق باستخدام GlassFish 3.1.1 جزءا لا يتجزأ مع JUnit 4.x و HtmlUnit 2.x و وضع المشروع كاملة للتحميل على Bitbucket هنا: صورة-بريمج

إذا كان لديك أي أسئلة, يرجى ترك تعليق.أعتقد أن هذا هو واحد كاملة سبيل المثال يمكنك استخدامها كأساس لأي اختبار كنت تخطط servlets.

هل استدعاء 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   
   }
}

حتى أنه من الأفضل أن تضع وهمية إنشاء طرق في قاعدة بريمج الفائقة وجعل كل سيرفلتس وحدة الاختبارات لتمديده.

Mockrunner (http://mockrunner.sourceforge.net/index.html) يمكن أن تفعل هذا.فإنه يوفر وهمية J2EE الحاويات التي يمكن استخدامها لاختبار Servlets.فإنه يمكن أيضا أن تستخدم لاختبار وحدة أخرى تعليمات برمجية من جانب الخادم مثل EJBs, JDBC, الدائرة, الدعامات.لقد استخدمت JDBC و EJB قدرات نفسي.

هذا تنفيذ JUnit اختبار بريمج doPost() طريقة تعتمد فقط على Mockito مكتبة برسم حالات HttpRequest, HttpResponse, HttpSession, ServletResponse و RequestDispatcher.استبدال المعلمة مفاتيح التخطيط الاستراتيجي المشترك javabean سبيل المثال مع تلك التي تتوافق مع القيم المشار إليها في المرتبطة الملف JSP التي doPost() يسمى.

Mockito مخضرم التبعية:

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

تحديث فبراير 2018: OpenBrace محدودة قد أغلقت, و ObMimic المنتج لم يعد معتمدا.

حل آخر هو استخدام بلدي ObMimic المكتبة التي تم تصميمها خصيصا اختبار الوحدة servlets.فإنه يوفر كامل عادي-Java تطبيقات كل بريمج API الطبقات ، يمكنك تهيئة وفحص هذه اللازمة الاختبارات الخاصة بك.

يمكنك بالفعل استخدام الاتصال مباشرة doGet/doPost أساليب من JUnit أو TestNG اختبارات لاختبار أي الطرق الداخلية حتى لو أنها تشير إلى ServletContext أو استخدام دورة المعلمات (أو أي بريمج ميزات API).

وهذا لا يحتاج خارجي أو جزءا لا يتجزأ من الحاوية ، لا حدود أوسع HTTP القائم على "التكامل" اختبارات على عكس الأغراض العامة يسخر له كامل بريمج API السلوك "خبز" ، لذلك الاختبارات الخاصة بك يمكن أن تكون "الدولة"وليس على أساس "التفاعل"على أساس (مثلا ، الاختبارات الخاصة بك لم يكن لديك إلى الاعتماد على تسلسل بريمج API المكالمات التي تتم من خلال الكود الخاص بك ، ولا على التوقعات الخاصة بك كيف بريمج API سيتم الرد على كل مكالمة).

هناك مثال بسيط في جوابي كيفية اختبار بلدي بريمج باستخدام JUnit.للحصول على التفاصيل الكاملة مجانا تحميل مشاهدة ObMimic موقع.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top