views:

2235

answers:

4

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 servlet context, but what about testing the doGet/doPost methods as well as the internal method that refer to the context or make use of session parameters?

Is there a way to do this simply using classical tools such as JUnit, or preferrably TestNG? Did I need to embed a tomcat server or something like that?

+2  A: 

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).

Peter Hilton
Well, it's really more about Unit Testing as I would, if possible, replace all the interaction between the servlet class with other classes by interaction with mocks.
gizmo
+4  A: 

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.

Marcio Aguiar
+4  A: 

Most of the time I test Servlets and JSP's via 'Integration Tests' rather than pure Unit Tests. There are a large number of add-ons for JUnit/TestNG available including:

  • HttpUnit (the oldest and best known, very low level which can be good or bad depending on your needs)
  • HtmlUnit (higher level than HttpUnit, which is better for many projects)
  • JWebUnit (sits on top of other testing tools and tries to simplify them - the one I prefer)
  • WatiJ and Selenium (use your browser to do the testing, which is more heavyweight but realistic)

This is a JWebUnit test for a simple Order Processing Servlet which processes input from the form 'orderEntry.html'. It expects a customer id, a customer name and one or more order items:

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;

}

Garth Gilmour
+1  A: 

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.

Kris Pruden