August 2003
[ vmassol ] 19:54, Saturday, 30 August 2003

The mock object strategy is nice but how do you apply it when you have some existing code that uses tons of static calls, does not have setters prepared so that you can introduce your mocks, etc?

One solution is to use AUT: AOP Unit Testing! (hehe... yet another acronym :-)).

Let's try that by writing a unit test using AspectJ for an EJB. Let's imagine we want to unit test the following createOrder() method:

package junitbook.ejb.service;

import java.rmi.RemoteException;
import java.util.Date;

import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;

import junitbook.ejb.domain.OrderLocal;
import junitbook.ejb.domain.OrderUtil;
import junitbook.ejb.util.JMSUtil;
import junitbook.ejb.util.JNDINames;

public abstract class PetstoreEJB implements SessionBean
{
     public int createOrder(Date orderDate, String orderItem)
     {
          OrderLocal order = OrderUtil.createOrder(orderDate, 
              orderItem);
  
          try
          {
               JMSUtil.sendToJMSQueue(JNDINames.QUEUE_ORDER, 
                   order.getOrderId(), false);
           }
          catch (Exception e)
          {
               throw new EJBException(e);
           }
          return order.getOrderId().intValue();
      }
 
     public void setSessionContext(SessionContext sessionContext) 
         throws EJBException, RemoteException {}
     public void ejbRemove() 
         throws EJBException, RemoteException {}
     public void ejbActivate() 
         throws EJBException, RemoteException {}
     public void ejbPassivate() 
         throws EJBException, RemoteException {}
}

Note that the nasty calls to OrderUtil.createOrder() and JMSUtil.sendToJMSQueue are static!

Our challenge here is to unit test this method in isolation from the rest. Here are the corresponding unit tests: one to verify it works when there is no exception (testCreateOrderOk ) and one to verify it also works when there is a JMS exception raised, for example (testCreateOrderWhenJMSException ):

package junitbook.ejb.service;

import java.util.Date;

import javax.ejb.EJBException;
import javax.jms.JMSException;

import com.mockobjects.dynamic.Mock;

import junit.framework.TestCase;
import junitbook.ejb.domain.OrderLocal;
import junitbook.ejb.domain.OrderUtil;
import junitbook.ejb.util.JMSUtil;

public class TestPetstoreEJB extends TestCase
{
     private PetstoreEJB ejb;
     
     protected void setUp()
     {
          this.ejb = new PetstoreEJB() {};
      } 
 
     public void testCreateOrderOk()
     {
          int result = this.ejb.createOrder(new Date(), "1234");
          assertEquals(1234, result);
      }
 
     public void testCreateOrderWhenJMSException()
     {
          try
          {
               this.ejb.createOrder(new Date(), "1234");
               fail("Should have thrown an EJBException");
           }
          catch (EJBException expected)
          {
               assertEquals("some jms error", 
                   expected.getCausedByException().getMessage());
           }
      }
}    

aspect TestPetstoreEJBAspect
{
     OrderLocal around():
         call(* OrderUtil.createOrder(..)) &&
         cflow(execution(* testCreateOrder*()))
     {
          Mock mockOrderLocal = new Mock(OrderLocal.class);
          OrderLocal orderLocal = (OrderLocal) mockOrderLocal.proxy();
          mockOrderLocal.matchAndReturn("getOrderId", new Integer(1234));
          return orderLocal;
      }
 
     void around():
         call(* JMSUtil.sendToJMSQueue(..)) &&
         cflow(execution(* testCreateOrderOk()))
     {
          return;
      }
 
     void around() throws JMSException:
         call(* JMSUtil.sendToJMSQueue(..)) &&
         cflow(execution(* testCreateOrderWhenJMSException()))
     {
          throw new JMSException("some jms error");
      }
}

Note: I highly recommend using Eclipse 3.0M3 and the latest AJDT plugin if you wish to run this code. The AJDT works great for writing AspectJ projects.

That's quite nice and it works nicely but as you have noticed the test code is neither very easy to write nor to read. What I would love is a dynamic language geared towards writing these kinds of unit tests! Could Groovy provide that? That would be soooooo nice!

[ vmassol ] 14:49, Saturday, 30 August 2003

James Strachan has posted a news about starting a new dynamic language for the java platform called Groovy. He mentions using it for writing unit tests a la JUnit.

I think that's an excellent idea! On most projects I've been on, writing good unit tests often comes late in the development. Usually people write functional or integration tests but rarely unit tests which test code in isolation from the rest. And once the design best practices have been decided and lots of code has been already written, writing unit tests is hard because it requires severe refactoring and design changes. The hard part is the introduce mock objects in the code under test. Some code uses statics, other instanciate domain objects instead of them being passed to it, etc.

Of course, extreme TDD practictioners would say that it is much better to refactor the code under test so that it become more flexible and better able to support change. That's true but that's difficult to practice for the majority of projects and difficult to apply if the project has not been started the TDD way.

What would be nice is to have a dynamic language geared towards introducing easily changes to the code so that it can support the mock objects approach. There is a unit testing framework out there that does almost this; it's called AgileTest from Polygenix.

Maybe Groovy could extend the ideas from AgileTest and become a generic dynamic language to easily insert mock objects (among other things)? Sprinkle this with an AspectJ-like syntax and you've got something quite nice!

I know I'm probably changing the original idea but what I'd love to have is a language purely geared towards unit testing

What do you think?

[ vmassol ] 17:53, Tuesday, 26 August 2003

About 2 years ago, I discovered the Concept Map idea and I began to do a simple proof of concept as shown by the following diagram.

simple unit testing map

Note that more thorough examples are available from the NASA web site.

I would like to revive this idea and start drawing some concept maps about the JUnit ecosystem. I would like to have some of these maps in my JUnit in Action book but I would also like to set up a collaborative web site gathering all knowledge around JUnit using these concept maps.

This is all nice but the software I used then (IHMC Concept Map Software) is now very old (2001), the GUI is flaky and the software does not lend too well to distributed updating of the maps on the web (it uses a custom server which opens a specific TCP/IP port and thus does not easily allow updates behind a firewall, etc).

I need your help! My questions to you are:

  1. Do you know how this concept has evolved? Is it still a hot topics nowadays?
  2. Do you know of any software (preferable free) that would allow me to easily draw maps such as the one above and allows collaborative editing over the web?

Thanks!