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();
}
}