Unit tests and EasyMock

Unit tests and EasyMock

Though I’ve heavily used refactoring for the past few years, I’ve never really felt at home with Test Driven Development. I’m glad to say that I’m really starting to see its merits.

Of course, as with every other technology, one must take care not to abuse it. For instance, seeing the “green light” can often lead to over-confidence. And it should, but only when the tests are thorough and well-designed.

So, in our latest project we’re building a small part of a web-services enabled system.I could never describe to you what it feels like to be able to unit test without needing the results of the other teams involved in the project. So far I had only tested relatively small, straightforward and isolated classes (such as utility classes) but it has always been a pain to test highly coupled classes.

Enter EasyMock from http://www.easymock.org/ …

This cute library enables you to easily mock up all the dependencies of each unit-tested class. The main package expects the dependencies to be interfaces (and that’s what i’ve used), but there’s also an additional library which also allows for concrete classes to be mocked up.

So, the idea is simple:

  • Get a reference to a mocked up interface.

             org.easymock.MockControl controlTTSCommLocator = MockControl.createControl(TTSCommManager.class);
             TTSCommManager mockTTSCommLocator = (TTSCommManager) controlTTSCommLocator.getMock();
     
  • Set it in the class to be unit-tested.

             programManager = new ProgramManagerImpl();
             programManager.setComLocator(mockTTSCommLocator);
     
  • Tell it what to do (i.e. train it)

             controlTTSCommLocator.expectAndReturn( mockTTSCommLocator.getTTSCommManagerSoap(), null );
     

    or

             controlMapLocator.expectAndThrow( mockMapLocator.getMapServerSoap(), new ServiceException() );
     
  • Let it play!

             controlTTSCommLocator.replay();
     
  • And finally, execute your tests as normal.

This process will instruct your mock object to expect the exact same calls as the ones you’ve already executed during training. In response to each call, it will either return when you’ve already told it to return, or throw an exception, again following your commands. So, your entire test will execute as normal but without actually making a call to (or requiring you to have) an implementation of the dependencies.

It’s very very handy, just try it!