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
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.
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).
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.
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.
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);
}
}
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.
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.
integration-test
as part of the executions of the surefire-pluginintegration-test
lifecycle.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>
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>
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.