I have a servlet called Calculator
. It reads the parameters left
, right
and op
and returns by setting an attribute result
in the response.
What is the easiest way to unit test this: basically I want to create an HttpServletRequest, set the parameters, and then checking the response - but how do I do that?
Here's the servlet code (it's small and silly on purpose):
public class Calculator extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
public Calculator() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Integer left = Integer.valueOf(request.getParameter("left"));
Integer right = Integer.valueOf(request.getParameter("right"));
Integer result = 0;
String op = request.getParameter("operator");
if ("add".equals(op)) result = this.opAdd(left, right);
if ("subtract".equals(op)) result = this.opSub(left, right);
if ("multiply".equals(op)) result = this.opMul(left, right);
if ("power".equals(op)) result = this.opPow(left, right);
if ("divide".equals(op)) result = this.opDiv(left, right);
if ("modulo".equals(op)) result = this.opMod(left, right);
request.setAttribute("result", result); // It'll be available as ${sum}.
request.getRequestDispatcher("index.jsp").forward(request, response);
}
}
...
}
Often, the important logic of a program is factored out into other classes, that are usable in a variety of contexts, instead of being tightly coupled to a Servlet Engine. This leaves the servlet itself as a simple adapter between the web and your application.
This makes the program easier to test, and easier to reuse in other contexts like a desktop or mobile app.
There are a few libraries out there that you can use. Are you using Spring http://www.springsource.org/ in your application? If so, there is one application for spring (spring-test) that contains MockHttpServletRequest. For example:
@Test
public void shouldReturnAValidaRedirectionMessage() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("op", "addition");
request.addParameter("left", "1");
request.addParameter("right", "5");
CalculatorServlet servlet = new CalculatorServlet();
Operation operation = servlet.getOperation(request);
assertNotNull(operation);
assertEquals(ADDITION, operation.getOperationType());
...
Check out ServletUnit. It's part of HttpUnit.
http://httpunit.sourceforge.net/doc/servletunit-intro.html
Can't say this is the best method to do so : but to unit test a simple servlet like that (one not using forwards, context etc..) what you could simply do is :
- Create mock HttpServletReqeust and HttpServletResponse instances using any mocking library. Even simpler would be using RequestWrapper and ResponseWrapper classes (simple custom classes implemented by extending the HttpServletReqeust and HttpServletResponse classes).
- On these mock (or custom) instances set certain properties - the parameters you want to test against in each test case - e.g.
op=add
for a addition unit test. If you are using custom classes, you can simply set them in an internal properties object. If you are using mocks, then settings expectations would do.
- Create an instance of the servlet -
new Calculator()
, keeping the required libs in the class path. Now call the service
method on this instance.
- When the call returns, get the o/p from the response class and assert it. Since the response class is again a custom class or a mocked version, this should be easy.
For mocking, a simply starting point would be EasyMock or Mockito (my fav)
An example for the wrapper : http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/http/HttpServletRequestWrapper.html
HTH
Generally you should abstract your business logic from Servlet container details. You can mock ServletRequest using Spring test package, but it would be a bad idea to simulate Servlet container. So, you should either run system tests on a real container or move your logic from servlet into a separate bean and test it in isolation.
public class Calculator {
public Integer calculate(Integer left, Integer right, String op) {
Integer result = 0;
if ("add".equals(op)) result = this.opAdd(left, right);
if ("subtract".equals(op)) result = this.opSub(left, right);
if ("multiply".equals(op)) result = this.opMul(left, right);
if ("power".equals(op)) result = this.opPow(left, right);
if ("divide".equals(op)) result = this.opDiv(left, right);
if ("modulo".equals(op)) result = this.opMod(left, right);
return result;
}
}
public class CalculatorServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Integer left = Integer.valueOf(request.getParameter("left"));
Integer right = Integer.valueOf(request.getParameter("right"));
String op = request.getParameter("operator");
Integer result = calculator.calculate(left, right, op);
request.setAttribute("result", result); // It'll be available as ${sum}.
request.getRequestDispatcher("index.jsp").forward(request, response);
}
}