The jMock framework comes with a JUnit 4.X runner for verifying the mock object states after each test run. Now with rules all the stuff of the runner can be done in one rule. I have implemented an example rule based on the JMock runner (see also jMock JIRA http://jira.codehaus.org/browse/JMOCK-237), here is the code of my example implementation:
import org.jmock.Mockery; import org.jmock.lib.AssertionErrorTranslator; import org.junit.Test; import org.junit.rules.MethodRule; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; public class JUnitRuleMockery extends Mockery implements MethodRule { public JUnitRuleMockery() { setExpectationErrorTranslator(AssertionErrorTranslator.INSTANCE); } public Statement apply(final Statement base, final FrameworkMethod method, Object target) { return new Statement() { @Override public void evaluate() throws Throwable { try { base.evaluate(); } catch(Throwable exp) { if(!isExceptionExpectedByTestMethod(exp, method)) { throw exp; } } assertIsSatisfied(); } }; } protected boolean isExceptionExpectedByTestMethod(Throwable exp, FrameworkMethod method) { Test test = method.getAnnotation(Test.class); return test.expected().equals(exp.getClass()); } }
Example Test which use the rule:
import org.eclipse.osgi.framework.console.CommandInterpreter; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.jmock.lib.legacy.ClassImposteriser; import org.junit.Before; import org.junit.Rule; import org.junit.Test;
// No jMock specific Runner needed only the default JUnit runner public class FrameworkCommandProviderTest {
@Rule public JUnitRuleMockery context = new JUnitRuleMockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }}; InternalSystemBundle mockInternalSystemBundle; Framework mockFramework; CommandInterpreter mockCommandInterpreter; FrameworkCommandProvider mockFrameworkCommandProvider; FrameworkCommandProvider frameworkCommandProvider; @Before public void setUp(){ // Create mock object for system bundle mockInternalSystemBundle = context.mock(InternalSystemBundle.class); // Mocking the getContext Method, returns always null context.checking(new Expectations() {{ allowing (mockInternalSystemBundle).getContext(); will(returnValue(null)); }}); // Create mock object for framework mockFramework = context.mock(Framework.class); // Set the mock object system bundle into the framework mock mockFramework.systemBundle = mockInternalSystemBundle; // Create mock object for command interpreter mockCommandInterpreter = context.mock(CommandInterpreter.class); // Create mock object for the SUT class, this mock will be used to mock methods in the SUT mockFrameworkCommandProvider = context.mock(FrameworkCommandProvider.class); // Create the SUT object of type FrameworkCommandProvider frameworkCommandProvider = new FrameworkCommandProvider(mockFramework) { /** * Mock the SUT Method getBundleFromToken(...) * All method calls will delegate to a mock * of the same type then the SUT object */ @Override protected AbstractBundle getBundleFromToken(CommandInterpreter intp, String token, boolean error) { // delegate the call to a mock object. return mockFrameworkCommandProvider.getBundleFromToken(intp, token, error); } }; } @Test(expected=RuntimeException.class) public void _bundle_OneArgumentsAndBundleNotFoundByToken() throws Exception { final String firstToken = "myBundleName[1.0.0]"; // Setup mock context context.checking(new Expectations() {{ // one argument one (mockCommandInterpreter).nextArgument(); will(returnValue(firstToken)); // next calles return null allowing (mockCommandInterpreter).nextArgument(); will(returnValue(null)); // getBundleFromToken returns null one (mockFrameworkCommandProvider).getBundleFromToken(mockCommandInterpreter, firstToken, true); will(returnValue(null)); }}); // invoke the _bundle() method frameworkCommandProvider._bundle(mockCommandInterpreter); throw new RuntimeException(); } }