Software Development, Agile Practices, Lean Thinking, Music
[ start | index | login or register ]
start > Unit Testing with StrutsTestCase and EasyMock

Unit Testing with StrutsTestCase and EasyMock

Created by brandon. Last edited by brandon, 302 days ago. Viewed 497 times. #9
[diff] [history] [edit] [rdf]
labels
attachments

Background

A common problem I have observed with Java web development using the Struts framework is the inability to easily unit test your Struts Actions. Even more difficult is the task of testing the Struts flow control without a running Servlet container (E.g. Tomcat, Jetty, WebSphere, etc.).

I have recently rolled the sleeves up and decided to dig into this for the Reference Implementation I am building for my organization. This Reference Implementation utilizes Struts and subsequently I am aiming to embody many best practices, including unit testing at every layer of the architecture.

The primary benefits of unit testing your Struts Actions are:

  • Support for Test Driven Development (Red, Green, Refactor!)
  • Assurance of flow control
  • Confidence in refactoring for both Actions and ActionForms
  • The unit test serves as a documented contract of the Action behavior
  • Lighter weight development environment, no container needed

Mocking to the Rescue

The concept of mocking drives this effort. The StrutsTestCase technology provides this via the MockStrutsTestCase class. In addition EasyMock provides a quick and concise way to specify the mock classes that are used from within your Struts Action.

For each unit test I have taken a two part testing approach:

  • Create a mock object using EasyMock to assert the behavior of the service implementation class that is being executed by the Struts Action.
  • Create a mock object using MockStrutsTestCase of the Struts environment to assert that the correct ActionForward is returned.

The Abstract Factory Design Pattern

In order to enable substitution of the service class I have applied the >>Abstract Factory pattern. The TestObjectFactory class is a concrete implementation of an abstract ObjectFactory class. At the time of unit testing I can easily insert a stub or mock service, while at runtime the SpringObjectFactory concrete implementation will provide the actual services from the Spring application context of the web application.
public abstract class ObjectFactory
{
    private static ObjectFactory instance;
    public abstract Object getBean(String beanName, ServletContext servletContext);
    public static synchronized ObjectFactory getInstance()
    {
        if (instance == null)
        {
            instance = new SpringObjectFactory();
        }

return instance; } public static synchronized void setInstance(ObjectFactory instance) { ObjectFactory.instance = instance; } } … public class TestObjectFactory extends ObjectFactory { private static HashMap beans = new HashMap();

public Object getBean(String beanName, ServletContext servletContext) { return beans.get(beanName); } public void addBean(String beanName, Object bean) { beans.put(beanName, bean); } } … public class SpringObjectFactory extends ObjectFactory {

public Object getBean(String beanName, ServletContext servletContext) { WebApplicationContext webContext = WebApplicationContextUtils .getWebApplicationContext(servletContext);

return webContext.getBean(beanName); } }

StrutsTestCase and MockStrutsTestCase

Example:
public class ReservationPersistActionTest extends MockStrutsTestCase
{
	private TestObjectFactory factory;

public void setUp() throws Exception { super.setUp(); factory = new TestObjectFactory(); ObjectFactory.setInstance(factory); setContextDirectory(new File("WebContent")); }

public void testExecute_CreateSuccess() { // create our mock service MockControl control = MockControl.createControl(IReservationService.class); IReservationService reservationService = (IReservationService) control.getMock();

// record expected mock state, behavior, and return value ReservationForm reservationForm = new ReservationFormStub(); IReservationBO reservation = new ReservationBO(); ((ReservationFormStub)reservationForm).setReservationBO(reservation); reservationForm.setOperation("create"); reservationService.create(reservation); ReservationTR transactionResult = new ReservationTR(); transactionResult.setSuccess(true); control.setReturnValue(transactionResult);

// replay state, activate mock for use control.replay();

// put the mock service into the test object factory // which is used by my struts Action factory.addBean( "reservationService", reservationService);

// Call the MockStrutsTestCase methods to specify URL path, form, etc. setRequestPathInfo("/reservation/persist"); setActionForm(reservationForm); actionPerform(); // Assert the action's forward verifyForward("success");

// Assert the mock service behaved as recorded control.verify(); } ...

References

4 comments (by anurekha_t, dennilee, brandon, perkar) | post comment
Describe here what your SnipSnap is about!

Configure this box!

  1. Login in
  2. Click here: snipsnap-portlet-2
  3. Edit this box
www.brandonburk.com | Copyright 2008 Brandon N. Burk