November 2003
[ vmassol ] 10:00, Monday, 24 November 2003

Junit in Action is now available in both ebook and printed format on Manning web site, Amazon and all good libraries.

Here are some resources about JIA:

Reviews:

  • Full review on TheServerSide.
  • Comments on TheServerSide following the post of 2 sample chapters.
  • Review on JavaRanch. The JavaRanch Testing forum is also currently discussing it. Additional comments by Jason Menard.
  • Review on Amazon.
  • [ vmassol ] 12:10, Sunday, 9 November 2003

    Joel Shellman has coded an extension (easymock-patch-1.0.jar) of EasyMock which allows to mock class (and not only interfaces).

    To use it:

    • put the extension jar in front of the easymock jar in your classpath (it works with Easymock 1.0 only, not with the new 1.0.1b which has modifications for extending Easymock). It overrides the MockControl class by a new one accepting a class as parameter as shown below.
    • add cglib to your classpath (I've tried it with version rc2-1.0).
    • add bcel to your classpath (I've tried it with version 5.1).

    Here's an example. First let's start by the class we wish to mock:

    package test;
    
    public class Calculator
    {
         private int amount;
         
         public Calculator(Integer amount)
         {
              this.amount = amount.intValue();
          }
         
         public int compute()
         {
              return this.amount;
          }
    }

    Here's now the class we wish to test (it uses the Calculator class):

    package test;
    
    public class Account
    {
         public int computeBalance(Calculator calculator)
         {
              return calculator.compute();
          }
    }

    Now, here's our test of computeBalance . Notice that we are mocking the Caculator class:

    package test;
    
    import org.easymock.MockControl;
    
    import junit.framework.TestCase;
    
    public class AccountTest extends TestCase
    {
         public void testComputeBalance()
         {
              Account test = new Account();
              
              MockControl control = MockControl.createControl(Calculator.class,
                  new Class[]{Integer.class}, new Object[]{new Integer(5)});
              Calculator mock = (Calculator) control.getMock();
              
              mock.compute();
              control.setDefaultReturnValue(10);
              control.replay();
              
              int result = test.computeBalance(mock);
              assertEquals(10, result);
          }
    }

    Note: I don't know how to instantiate a constructor taking primitive types. Don't know if it is supported.

    That's nice. However, there are a few drawbacks I can see:

    • It doesn't encourage refactoring and creating interfaces (which is the right way to go in most cases). However, it can still be useful in some cases like when mocking third party classes which do not have interfaces (and there are quite a lot of them, especially in the JDK...)
    • It doesn't work with final classes. Thus not possible to mock the JDK's URL class for example. It also won't work with private constructors of course
    • It forces to know the constructor values when creating the mock
    • It still doesn't help in cases where it is no easy to introduce the mock in the class under test. In that regards, it's less powerful than interception (a la AOP).

    So it's not a silver bullet but it will certainly help in cases where you have no control over the sources (like when using third-party libraries.