Unit testing a Java Servlet

后端 未结 8 1677
心在旅途
心在旅途 2020-11-28 21:05

I would like to know what would be the best way to do unit testing of a servlet.

Testing internal methods is not a problem as long as they don\'t refer to the servl

相关标签:
8条回答
  • 2020-11-28 21:37

    Are you calling the doPost and doGet methods manually in the unit tests? If so you can override the HttpServletRequest methods to provide mock objects.

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

    The HttpServletRequestWrapper is a convenience Java class. I suggest you to create a utility method in your unit tests to create the mock http requests:

    public void testSomething() {
        myServlet.doGet(createMockRequest(), createMockResponse());
    }
    
    protected HttpServletRequest createMockRequest() {
       HttpServletRequest request = new HttpServletRequestWrapper() {
            //overrided methods   
       }
    }
    

    It's even better to put the mock creation methods in a base servlet superclass and make all servlets unit tests to extend it.

    0 讨论(0)
  • 2020-11-28 21:39

    Try HttpUnit, although you are likely to end up writing automated tests that are more 'integration tests' (of a module) than 'unit tests' (of a single class).

    0 讨论(0)
  • 2020-11-28 21:54

    Mockrunner (http://mockrunner.sourceforge.net/index.html) can do this. It provides a mock J2EE container that can be used to test Servlets. It can also be used to unit test other server-side code like EJBs, JDBC, JMS, Struts. I've only used the JDBC and EJB capabilities myself.

    0 讨论(0)
  • 2020-11-28 21:56

    This Question has a solution proposing Mockito How to test my servlet using JUnit This limits the task to simple unit testing, without setting up any server-like environment.

    0 讨论(0)
  • 2020-11-28 21:59

    This implementation of a JUnit test for servlet doPost() method relies only on the Mockito library for mocking up instances of HttpRequest, HttpResponse, HttpSession, ServletResponse and RequestDispatcher. Replace parameter keys and JavaBean instance with those that correspond to values referenced in the associated JSP file from which doPost() is called.

    Mockito Maven dependency:

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

    JUnit test:

    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 讨论(0)
  • 2020-11-28 22:01

    I looked at the posted answers and thought that I would post a more complete solution that actually demonstrates how to do the testing using embedded GlassFish and its Apache Maven plugin.

    I wrote the complete process up on my blog Using GlassFish 3.1.1 Embedded with JUnit 4.x and HtmlUnit 2.x and placed the complete project for download on Bitbucket here: image-servlet

    I was looking at another post on an image servlet for JSP/JSF tags just before I saw this question. So I combined the solution I used from the other post with a complete unit tested version for this post.

    How to Test

    Apache Maven has a well defined lifecycle that includes test. I will use this along with another lifecycle called integration-test to implement my solution.

    1. Disable standard lifecycle unit testing in the surefire plugin.
    2. Add integration-test as part of the executions of the surefire-plugin
    3. Add the GlassFish Maven plugin to the POM.
    4. Configure GlassFish to execute during the integration-test lifecycle.
    5. Run unit tests (integration tests).

    GlassFish Plugin

    Add this plugin as part of the <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>
    

    Surefire Plugin

    Add/modify the plugin as part of the <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

    Add integration tests like the example below.

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

    I wrote the complete process up on my blog Using GlassFish 3.1.1 Embedded with JUnit 4.x and HtmlUnit 2.x and placed the complete project for download on Bitbucket here: image-servlet

    If you have any questions, please leave a comment. I think that this is one complete example for you to use as the basis of any testing you are planning for servlets.

    0 讨论(0)
提交回复
热议问题