Java

Mocking a Stub with EasyMock

I use EasyMock extensively to create mock objects for unit testing. The behavior verification is great for thoroughly testing an object’s interactions with other objects, known as collaborators. Sometimes, however, a mock cannot do all that is needed. Martin Fowler, in his article “Mocks aren’t Stubs”, identifies injected collaborators, or “test doubles”, as being mocks or stubs. Using EasyMock, it is possible to create an object which is both.

I recently ran into a scenario where I needed such a hybrid. Consider save method the following Struts action. This method handles both new and existing products, differentiated by the nullity of the id property of product.

Here is the class under test:

public class CustomerEditAction extends ActionSupport implements Preparable {

  private CustomerDao customerDao;
  private Long id;
  private Customer customer;

  public void setCustomerDao(CustomerDao customerDao) {
    this.customerDao = customerDao;
  }
  public Long getId() {
    return id;
  }
  public void setId(Long id) {
    this.id = id;
  }
  public Customer getCustomer() {
    return customer;
  }
  public void setCustomer(Customer customer) {
    this.customer = customer;
  }

  public void prepare() throws Exception {
    /* Sets up the id and the customer.  Removed for brevity */
  }

  public String save() {

    if (customer.getId() == null) {
      customerDao.insert(customer);
      setId(customer.getId());
  } else {
    customerDao.update(customer);
  }

  return Action.SUCCESS;
}

And here is the collaborating dao:

public interface CustomerDao {

  List getAll();

  Customer getForId(Long id);

  void insert(Customer customer);

  void update(Customer customer);

}

Testing the “update” case of the save method where product.getId() is not null with a mock object is simple, all we need to verify that the update method of product dao is called with the right argument.

The “insert” case is not as straightforward, and is a case where a simple mock is not sufficient.
This issue is with verifying the additional step of setting the id of the product to the action after the insert is performed. It is assumed that the productDao itself modifies the id of the product after inserting it into the database. Since a mock object is just an empty shell which follow scripted behaviors without any implementation, there is no way to use one to actually modify the product as the actual dao would. But without actually modifying the product passed as an argument to productDao, there is no way to verify that the id property of the action is set with the value from the id property of the product. The alternative is to use a stub in our test case instead of a mock, like the following:

private static abstract class StubCustomerDao implements CustomerDao {

  static final Long ID = 9999L;

  public void insert(Customer customer) {
    customer.setId(ID);
  }

}

The class is actually an inner class of my test class. It is abstract for a reason - keep reading for the explanation.

The resulting unit test for the insert case would be:

public class CustomerEditActionTest {

  private CustomerEditAction action;
  private StubCustomerDao customerDao;
  private Long id;
  private Customer customer;

  @Before
  public void setUp() throws Exception {

    action = new CustomerEditAction();

    /*
    * Here we are creating a mock of our stub, a private inner class
    */
    customerDao = createMock(StubCustomerDao.class,
    StubCustomerDao.class.getMethod("getForId", Long.class),
    StubCustomerDao.class.getMethod("update", Customer.class));

    id = 1L;
    customer = new Customer();
    customer.setId(id);

    action.setCustomerDao(customerDao);
  }

  /* Some tests removed for brevity */

  @Test
  public void testSaveInsert() {

    reset(customerDao);
    customer.setId(null);
    action.setCustomer(customer);
    replay(customerDao);
    assertSame("result not success", Action.SUCCESS, action.save());
    assertEquals("customer id is equals", StubCustomerDao.ID,
    action.getId());
    verify(customerDao);

  }

  @Test
  public void testSaveUpdate() {

    reset(customerDao);
    action.setCustomer(customer);
    customerDao.update(customer);
    replay(customerDao);
    assertSame("result not success", Action.SUCCESS, action.save());
    verify(customerDao);

  }

  /* Stub class */
  private static abstract class StubCustomerDao implements CustomerDao {

    static final Long ID = 9999L;

    public void insert(Customer customer) {
      customer.setId(ID);
    }
  }

}

Switching from a mock to a stub for the insert method means that I am exclusively verifying state, and no longer verifying behavior. Asserting that the product id and the action have the correct value in their id property gives me reasonable assurance that the action is doing what I want it to do.

But why an abstract class for ProductDaoStub? Because I only want to use a stub for this one test method. It still makes sense to use a mock for calls to to the other methods of the class, like update and getForId. This is where the class extension of EasyMock really shines. With the class extension MockControl, mocks can be created from concrete types, like HttpServletRequest, not just from interface types like ProductDao. By default, a class mock causes all methods to be mocked. You can, however, specify that only certain methods be mocked, and the rest of the class methods are invoked in the class itself. I am using this feature to mock my stub. This gives me all of the power of a mock and the ability to carve out a stub for the one method which needs it. This table shows the effect:

Mock Stub

Method interface ProductDao ProductDaoStub Mock of ProductDaoStub Net Effect
getAll unimplemented unimplemented unimplemented unimplemented
getForId unimplemented unimplemented mocked mocked
insert unimplemented stubbed unimplemented stubbed
update unimplemented unimplemented mocked stubbed

The full code can be browsed here and checked out with the following command:

svn co http://bentomasini.com/svn/repo1/demos/mockstub/tags/TAG-mockingAStub mockstub

Update: Fixed a bug in the unit test where the customer’s id was being asserted and not the action’s id. That kinda misses the whole point.

“Getting” IoC

Howard Lewis Ship has added an IoC Overview document to the Tapestry IoC project. It’s goal is an important one, helping developers “get” IoC.

For me, “getting” IoC was a big event. It happened to me in early 2004 when I was working on a workflow engine for a large back office application for a bank. A friend of mine told me I should check out HiveMind (the predecessor to Tapestry IoC). Using it, I found I was able to develop more sophisticated, more testable code with less grunt work. The dots between object oriented design and application assembly were connected elegantly.

The document mentions that style of code that works best when using an IoC container:

When thinking in terms of IoC, small is beautiful. What does that mean? It means small classes and small methods are easier to code than large ones. At one extreme, we have servlets circa 1997 (and Visual Basic before that) with methods a thousand lines long, and no distinction between business logic and view logic. Everything mixed together into an untestable jumble.

At the other extreme is IoC: small objects, each with a specific purpose, collaborating with other small objects.

Using unit tests, in collaboration with tools such as EasyMock, you can have a code base that is easy to maintain, easy to extend, and easy to test. And by factoring out a lot of plumbing code, your code base will not only be easier to work with, it will be smaller.

The document ends with the concept that IoC does for object creation what garbage collection does for object destruction: takes it out of your hands and does it better (here is an older blog post on that same topic). I think the Guice project captures this concept the best when describing their @Inject annotation, calling it “the new new“.

A Simple Approach to Axis2

I recently started searching for a SOAP framework and took a look at Axis2. Actually, I looked at it twice. The first time I passed because the deployment model was too confusing. Only after evaluating the downsides of the other frameworks did I take a second look. I eventually went with it after I figured out how to get it to meet my two main requirements:

  1. A simple coding and deployment model: I didn’t something so complex that a wizard has to hide the complexity from me. I especially didn’t want a hot deployment of a special archive into a magic axis webapp. Just give me a simple configuration file to edit or some annotations for my service classes.
  2. IoC container integration. Instead of directly instantiating a service class and calling a method, I wanted Axis2 to invoke a method on one of my services defined in my IoC container (Spring, in this case).

I put together a sample project which demonstrates a simple approach to Axis2. The application exposes a single web service for retrieving products from a catalog. The service has two methods: getAll, and getForId.

Getting and Running the Project

The sample project can be found at http://bentomasini.com/svn/repos/demos/catalog/trunk. To try it out, checkout the source and start the application by doing the following. Maven2 is required.

svn co http://bentomasini.com/svn/repos/demos/catalog/trunk catalog
cd catalog
mvn jetty:run

Now open http://localhost:8080/catalog. From there you can open the WSDL and run a few operations using the quasi-RESTful Axis2 interface. To call the service using SOAP, or to generate clients for various SOAP frameworks, I recommend using soapUI. Just create a new WSDL project using the WSDL URL linked from the home page.

Java Code and Spring Configuration

The project’s service class, shown below, calls the injected dao and converts List<Product> to Product[]. SOAP frameworks choke on collections.

package com.bentomasini.catalog;

import com.bentomasini.catalog.Product;
import com.bentomasini.catalog.dao.ProductDao;

/**
*
* @author btomasini
* @since Jul 15, 2007
*
*/

public class ProductService {

    private ProductDao productDao;

    public void setProductDao(ProductDao productDao) {
        this.productDao = productDao;
    }

    public Product[] getAll() {
        return productDao.getAll().toArray(new Product[0]);
    }

    public Product getForId(Long id) {
        return productDao.getForId(id);
    }

}

The applicationContext.xml located in WEB-INF wires up the Spring bean and its dao:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">  

  <bean id="productDao" class="com.bentomasini.catalog.dao.impl.ProductDaoImpl"/>

  <bean id="productService" class="com.bentomasini.catalog.ProductService">
    <property name="productDao" ref="productDao" />
  </bean>

</beans>

Axis2 Configuration and web.xml

The method I used to configure Axis2 is key to keeping the project simple. It also requires some background explanation. The Axis2 folks have a concept that developers should package their web services in a new type of archive, an aar, and deploy that aar into a canned Axis2 web application. This makes me scratch my head and go “huh?” I don’t think most developers want to do this. I know I don’t. I simply want to build a web application, specify some services, and package my application in one single application archive - a war.

The good news is that developers don’t have to create aar archive files. Taking a look at the aar deployment model, we see that these service archives are deployed into WEB-INF/services. Alternatively, service archives can be exploded into a directory by the same base name. So WEB-INF/services/ProjectService.aar can instead by deployed by exploding its contents into the directory WEB-INF/services/ProjectService. The magic file in the archive is META-INF/services.xml. It defines the services to be deployed by Axis2. This file can contain a single service definition, or multiple service definitions inside of a service-group element.

We can do away with all of this hoo-ha by having a single services.xml for our entire project. Just pick a generic name for the directory, say “WebService”. Now we can put a single file in our project to define services: WEB-INF/services/WebService/META-INF/services.xml. Just put all of your service definitions in there and enjoy the simplicity. Here is the services.xml file from the sample project:

<?xml version="1.0" encoding="UTF-8"?>
<serviceGroup>

  <service name="ProductService">
    <parameter name="ServiceObjectSupplier" locked="false">
      org.apache.axis2.extensions.spring.receivers.SpringServletContextObjectSupplier
    </parameter>
    <parameter name="SpringBeanName" locked="false">productService</parameter>
    <operation name="getForId">
      <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
    </operation>
    <operation name="getAll">
      <messageReceiver class="org.apache.axis2.rpc.receivers.RPCMessageReceiver"/>
    </operation>
    <excludeOperations>
      <operation>setProductDao</operation>
    </excludeOperations>
  </service>

  <!-- Add your second service here -->

</serviceGroup>

The service element configures our service for deployment and specifies a special ServiceObjectProvider which knows how to obtain the service from our Spring context. The name of the Spring bean is also provided. Each operation has an operation element and text marking it as an RPC method. In addition, our setProductDao method is excluded because it is only meant for use by our IoC container for dependency injection. Adding another operation or service is simply a cut-and-paste exercise.

The web.xml to load both Spring and Axis2:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
  PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>AxisServlet</servlet-name>
    <servlet-class>org.apache.axis2.transport.http.AxisServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>AxisServlet</servlet-name>
    <url-pattern>/services/*</url-pattern>
  </servlet-mapping>
</web-app>

That’s it!

Fully Qualified Artifact Names

There is a lot to like about Restlet, including even the the way they name their artifacts. You can check it out in their maven repository. Instead of just naming their jar restlet-1.0.1.jar, they name it with the full base package name: org.restlet-1.0.1.jar.  That name better represents the actual name of the module.  It also makes it easier to track down which class belongs to which jar, which can be helpful when you have to manually assemble a set of jars for a driver or other resource connector not in your main project.

I am going to adopt this convention for my projects from here on out, and hope other projects will as well.

Creating a Swing Test Runner for Maven 2

I have been a devoted Emacs user since a co-worker introduced it to me in 2001. Emacs’ efficient layout of keystrokes enables me to work faster and longer with less hand fatigue than other editors. My optimal Java development environment is a bash shell (Cygwin if using Windows), Emacs, and a good build tool such as Maven. I feel a sense of commitment to this setup since I have been using it for over 6 years now.

Recently I have been switching projects from Maven 1 to Maven 2. This has been great except for the fact that Maven 2 does not have a GUI test runner for unit tests. Suddenly my optimal development environment is missing a test runner. In Maven 1, the test:ui goal would invoke the org.juint.swing.SwingRunner. There is an open issue for this in the Surefire JIRA to add back the GUI support to the command line, but it doesn’t look like it will be addressed any time soon.

So what to do?

One solution is to bite the bullet and join the rest of the world and use an IDE like Eclipse. This is definitely the path of least resistance. I have tried this, but it just hasn’t worked for me. I simply don’t flow as well with Eclipse.

I am thinking that the best solution is to create a Swing test runner for Maven 2. I have been looking at what this will take and have identified some components of a design. Here goes:

  • I would focus solely on TestNG for now.
  • It would be nice if the test runner did not need to be restarted after each compilation. I could see myself keeping the test runner window open, and issuing mvn compile commands in a separate window.
  • The test runner would need to fork the execution of the tests - running them in a completely separate class loader. This in itself would not be difficult. The test runner would just instantiate Surefire in the same way that the Maven Surefire plug-in does.
  • Surefire would need to know about the classpath. This could be done differently depending if the test runner were invoked from maven or from the command line.
  • The real challenge would involve reporting test events from the tests running in the surefire class loader back to the Swing application. The Eclipse plug-in for TestNG uses the RemoteTestNG class and a set of socket communications back to the GUI. I expect something similar would need to be done.

I expect to have some progress on this over the next couple of weeks, as spare time permits.