Mocking Classes with jMock and the ClassImposteriser

Because it uses Java's standard reflection capability, the default configuration of the jMock framework can only mock interfaces, not classes. (Actually, we consider that to be a good thing because it encourages the design to focus on communication between objects rather than static classification or data storage). However, the ClassImposteriser extension class uses the CGLIB 2.11 and Objenesis2 libraries to create mock objects of classes as well as interfaces. This is useful when working with legacy code to tease apart dependencies between tightly coupled classes.

The ClassImposteriser creates mock instances without calling the constructor of the mocked class. So classes with constructors that have arguments or call overideable methods of the object can be safely mocked. However, the ClassImposteriser cannot create mocks of final classes or mock final methods.

If you want to mock final classes or final methods, the JDave library3 includes an unfinalizer Instrumentation agent4 that can unfinalise classes before they are loaded by the JVM. They can then be mocked by the ClassImposteriser.

To use the ClassImposteriser:

  1. Add jmock-legacy-2.6.1.jar, cglib-nodep-2.1_3.jar and objenesis-1.0.jar to your CLASSPATH.
  2. Plug the ClassImposteriser into the Mockery of your test class:

    Raw

    import org.jmock.Mockery;
    import org.jmock.Expectations;
    import org.jmock.lib.legacy.ClassImposteriser;
    
    public class ConcreteClassTest extends TestCase {
        private Mockery context = new Mockery() {{
            setImposteriser(ClassImposteriser.INSTANCE);
        }};
        
        ...
    }

    JUnit 3

    import org.jmock.Expectations;
    import org.jmock.integration.junit3.MockObjectTestCase;
    import org.jmock.lib.legacy.ClassImposteriser;
    
    public class ConcreteClassTest extends MockObjectTestCase {
        {
            setImposteriser(ClassImposteriser.INSTANCE);
        }
        
        ...
    }

    JUnit 4

    import org.jmock.Mockery;
    import org.jmock.Expectations;
    import org.jmock.integration.junit4.JUnit4Mockery;
    import org.jmock.lib.legacy.ClassImposteriser;
    
    @RunWith(JMock.class)
    public class ConcreteClassTest {
        private Mockery context = new JUnit4Mockery() {{
            setImposteriser(ClassImposteriser.INSTANCE);
        }};
        
        ...
    }
  3. Your tests can now create mocks of abstract or even concrete classes:
    Graphics g = context.mock(java.awt.Graphics.class);

Links:

1. CGLIB 2.1: http://cglib.sourceforge.net

2. Objenesis: http://code.google.com/p/objenesis/

3. JDave library: http://www.jdave.org

4. unfinalizer Instrumentation agent: http://www.jdave.org/documentation.html#mocking