Search code examples
javajunitjmock

Lack of support base class in Junit4/Jmock2


We're finally migrating our unit test code base from JUnit 3 to JUnit 4. We also make heavy use of JMock 2.

With JUnit 3, JMock provides a useful base class for your tests (MockObjectTestCase), which as well as itself being s subclass of Junit's TestCase, it handles various housekeeping duties regarding the mock framework. It makes life pretty easy for the test class.

Now with JUnit4, JMock provides no such support. Your test class has to manually create a Mockery object, it has to remember to use the correct test runner annotation, and must delegate all mock-related operations to the mockery. In short, it puts far more responsibility on the test class than was needed for JUnit 3 tests.

Now I appreciate that part of JUnit4's charm is there being no need to subclass something, but this JMock situation seems like a step backwards, and makes porting from 3 to 4 rather more work than should be necessary.

Am I missing something? Is there actually a nice way to write my JUnit4/Jmock2 test classes without manually adding all that plumbing to every class? I could write my own support base class, of course, but it seems such an obvious omission from the JMock2 API, I have to wonder if I've missed the point.


Edit: here's the source code of what the optional support class would look like:

@RunWith(JMock.class)
public class JMockSupport {

    protected final Mockery mockery = new Mockery();

    protected void checking(ExpectationBuilder expectations) {
        mockery.checking(expectations);
    }

    protected <T> T mock(Class<T> typeToMock) {
        return mockery.mock(typeToMock);
    }

    protected <T> T mock(Class<T> typeToMock, String name) {
        return mockery.mock(typeToMock, name);
    }

    protected Sequence sequence(String name) {
        return mockery.sequence(name);
    }

    protected void setDefaultResultForType(Class<?> type, Object result) {
        mockery.setDefaultResultForType(type, result);
    }

    protected void setImposteriser(Imposteriser imposteriser) {
        mockery.setImposteriser(imposteriser);
    }

    protected void setNamingScheme(MockObjectNamingScheme namingScheme) {
        mockery.setNamingScheme(namingScheme);
    }

    protected States states(String name) {
        return mockery.states(name);
    }
}

This contains all of the methods that the JUnit3 MockObjectTestCase class defined, which just echo to the mockery. The @RunWith annotation is there also, to avoid the possibility of forgetting to add it to your test class.


Solution

  • There are also problems with having base classes. In previous versions, I suffered from trying to combine base classes from different test frameworks. That's why we went to composition over inheritance. It'll be interesting to see what we can do with the new @Rule structure.