Last days I have created a small utility class that would allow me to work with JMock without depending on JUnit. If you develop tests using TestNG and you need mocks a la JMock, than here it is (I have removed the imports so that the listing doesn’t go too long):
/** * An utility class to allow static usage of JMock (removes the restriction * to subclass JMock specific classes). * * @author Alexandru Popescu */ public class JMock { static final Constraint ANYTHING = new IsAnything(); private static final WeakHashMap<Thread, List<Verifiable>> s_mockObjects = new WeakHashMap<Thread, List<Verifiable>>(); /** * Creates a mock object that mocks the given type. * The mock object is named after the type; the exact * name is calculated by {@link #defaultMockNameForType}. * * @param mockedType The type to be mocked. * @return A {@link Mock} object that mocks <var>mockedType</var>. */ public static Mock mock(Class mockedType) { return mock(mockedType, defaultMockNameForType(mockedType)); } /** * Creates a mock object that mocks the given type and is explicitly given a name. * The mock object is named after the type; * the exact name is calculated by {@link #defaultMockNameForType}. * * @param mockedType The type to be mocked. * @param roleName The name of the mock object * @return A {@link Mock} object that mocks <var>mockedType</var>. */ public static Mock mock( Class mockedType, String roleName ) { Mock newMock = new Mock(newCoreMock(mockedType, roleName)); registerToVerify(newMock); return newMock; } public static Mock mock(Class mockedClass, String roleName, Class[] constructorArgumentTypes, Object[] constructorArguments) { Mock newMock = new Mock(newClassCoreMock(mockedClass, roleName, constructorArgumentTypes, constructorArguments)); registerToVerify(newMock); return newMock; } public static Mock mock(Class mockedClass, Class[] constructorArgumentTypes, Object[] constructorArguments) { return mock(mockedClass, defaultMockNameForType(mockedClass), constructorArgumentTypes, constructorArguments); } public static Stub returnValue(Object o) { return new ReturnStub(o); } public static Stub returnValue(boolean result ) { return returnValue(new Boolean(result)); } public static Stub returnValue(byte result ) { return returnValue(new Byte(result)); } public static Stub returnValue(char result ) { return returnValue(new Character(result)); } public static Stub returnValue(short result ) { return returnValue(new Short(result)); } public static Stub returnValue(int result ) { return returnValue(new Integer(result)); } public static Stub returnValue(long result ) { return returnValue(new Long(result)); } public static Stub returnValue(float result ) { return returnValue(new Float(result)); } public static Stub returnValue(double result ) { return returnValue(new Double(result)); } public static Stub returnIterator(Collection collection) { return new ReturnIteratorStub(collection); } public static Stub returnIterator(Object[] array) { return new ReturnIteratorStub(array); } public static Stub throwException(Throwable throwable) { return new ThrowStub(throwable); } public static InvocationMatcher once() { return new InvokeOnceMatcher(); } public static InvocationMatcher atLeastOnce() { return new InvokeAtLeastOnceMatcher(); } public static InvocationMatcher exactly(int expectedCount) { return new InvokeCountMatcher(expectedCount); } public static InvocationMatcher never() { return new TestFailureMatcher("not expected"); } public static InvocationMatcher never( String errorMessage ) { return new TestFailureMatcher("not expected ("+errorMessage+")"); } public static Stub onConsecutiveCalls(Stub... stubs) { return new StubSequence(stubs); } public static Stub doAll(Stub... stubs) { return new DoAllStub(stubs); } public static IsEqual eq(Object operand) { return new IsEqual(operand); } public static IsEqual eq(boolean operand ) { return eq(new Boolean(operand)); } public static IsEqual eq(byte operand ) { return eq(new Byte(operand)); } public static IsEqual eq(short operand ) { return eq(new Short(operand)); } public static IsEqual eq(char operand ) { return eq(new Character(operand)); } public static IsEqual eq(int operand ) { return eq(new Integer(operand)); } public static IsEqual eq(long operand ) { return eq(new Long(operand)); } public static IsEqual eq(float operand ) { return eq(new Float(operand)); } public static IsEqual eq(double operand ) { return eq(new Double(operand)); } public static IsCloseTo eq( double operand, double error ) { return new IsCloseTo(operand, error); } public static IsSame same( Object operand ) { return new IsSame(operand); } public static IsInstanceOf isA( Class operandClass ) { return new IsInstanceOf(operandClass); } public static StringContains stringContains(String substring) { return new StringContains(substring); } public static StringContains contains(String substring) { return stringContains(substring); } public static StringStartsWith startsWith(String substring ) { return new StringStartsWith(substring); } public static StringEndsWith endsWith(String substring ) { return new StringEndsWith(substring); } public static IsNot not(Constraint c ) { return new IsNot(c); } public static And and(Constraint left, Constraint right ) { return new And(left, right); } public static Or or(Constraint left, Constraint right ) { return new Or(left, right); } /// HINT: not sure about these following 3 public static Object newDummy( Class dummyType ) { return Dummy.newDummy(dummyType); } /// HINT: what is this? public static Object newDummy( Class dummyType, String name ) { return Dummy.newDummy(dummyType, name); } /// HINT: what is this? public static Object newDummy( String name ) { return Dummy.newDummy(name); } public static void assertThat(Object actual, Constraint constraint) { if (!constraint.eval(actual)) { StringBuffer message = new StringBuffer("\nExpected: "); constraint.describeTo(message); message.append("\n got : ").append(actual).append('\n'); throw new AssertionError(message); } } public static void assertThat(boolean actual, Constraint constraint) { assertThat(new Boolean(actual), constraint); } public static void assertThat(byte actual, Constraint constraint) { assertThat(new Byte(actual), constraint); } public static void assertThat(short actual, Constraint constraint) { assertThat(new Short(actual), constraint); } public static void assertThat(char actual, Constraint constraint) { assertThat(new Character(actual), constraint); } public static void assertThat(int actual, Constraint constraint) { assertThat(new Integer(actual), constraint); } public static void assertThat(long actual, Constraint constraint) { assertThat(new Long(actual), constraint); } public static void assertThat(float actual, Constraint constraint) { assertThat(new Float(actual), constraint); } public static void assertThat(double actual, Constraint constraint) { assertThat(new Double(actual), constraint); } public static HasPropertyWithValue hasProperty(String propertyName, Constraint expectation) { return new HasPropertyWithValue(propertyName, expectation); } public static HasProperty hasProperty(String propertyName) { return new HasProperty(propertyName); } public static HasToString toString(Constraint toStringConstraint) { return new HasToString(toStringConstraint); } public static IsCompatibleType compatibleType(Class baseType) { return new IsCompatibleType(baseType); } public static IsIn isIn(Collection collection) { return new IsIn(collection); } public static IsIn isIn(Object[] array) { return new IsIn(array); } public static IsCollectionContaining collectionContaining(Constraint elementConstraint) { return new IsCollectionContaining(elementConstraint); } public static IsCollectionContaining collectionContaining(Object element) { return collectionContaining(eq(element)); } public static IsArrayContaining arrayContaining(Constraint elementConstraint) { return new IsArrayContaining(elementConstraint); } public static IsArrayContaining arrayContaining(Object element) { return arrayContaining(eq(element)); } public static IsArrayContaining arrayContaining(boolean element) { return arrayContaining(new Boolean(element)); } public static IsArrayContaining arrayContaining(byte element) { return arrayContaining(new Byte(element)); } public static IsArrayContaining arrayContaining(short element) { return arrayContaining(new Short(element)); } public static IsArrayContaining arrayContaining(char element) { return arrayContaining(new Character(element)); } public static IsArrayContaining arrayContaining(int element) { return arrayContaining(new Integer(element)); } public static IsArrayContaining arrayContaining(long element) { return arrayContaining(new Long(element)); } public static IsArrayContaining arrayContaining(float element) { return arrayContaining(new Float(element)); } public static IsArrayContaining arrayContaining(double element) { return arrayContaining(new Double(element)); } public static IsMapContaining mapContaining(Constraint keyConstraint, Constraint valueConstraint) { return new IsMapContaining(keyConstraint, valueConstraint); } public static IsMapContaining mapContaining(Object key, Object value) { return mapContaining(eq(key), eq(value)); } public static IsMapContaining mapWithKey(Object key) { return mapWithKey(eq(key)); } public static IsMapContaining mapWithKey(Constraint keyConstraint) { return new IsMapContaining(keyConstraint, ANYTHING); } public static IsMapContaining mapWithValue(Object value) { return mapWithValue(eq(value)); } public static IsMapContaining mapWithValue(Constraint valueConstraint) { return new IsMapContaining(ANYTHING, valueConstraint); } /** * Verify the expected behavior for the mock registered by the current thread. */ public static void verify() { List<Verifiable> mocks = s_mockObjects.get(Thread.currentThread()); if(null != mocks) { for(Verifiable verifiable : mocks) { verifiable.verify(); } } } /** * Verify the expected behavior for the mocks defined as fields of the arguement object. * * @param object the object to be inspected */ public static void verifyObject(Object object) { Verifier.verifyObject(object); } /** * Helper method that delegates to {@link #verify()} and {@link verifyObject(Object)}. */ public static void verifyAll(Object object) { verify(); verifyObject(object); } /** * Verify the expected behavior for the mocks registered by the current thread and * also releases them. */ public static synchronized void verifyAndRelease() { Thread currentThread= Thread.currentThread(); List<Verifiable> mocks = s_mockObjects.get(currentThread); if(null != mocks) { for(Verifiable verifiable : mocks) { verifiable.verify(); } } mocks.clear(); s_mockObjects.put(currentThread, null); } /** * Helper method delegating to {@link #verifyAndRelease()} and {@link #verifyObject(Object)}. */ public static void verifyAllAndRelese(Object object) { verifyAndRelease(); verifyObject(object); } /// private static synchronized void registerToVerify(Verifiable verifiable) { List<Verifiable> mocks = s_mockObjects.get(Thread.currentThread()); if(null == mocks) { mocks = new ArrayList<Verifiable>(); s_mockObjects.put(Thread.currentThread(), mocks); } mocks.add(verifiable); } private static DynamicMock newCoreMock(Class mockedType, String roleName ) { return new CoreMock(mockedType, roleName); } private static DynamicMock newClassCoreMock(Class mockedClass, String roleName, Class[] constructorArgumentTypes, Object[] constructorArguments) { return new CGLIBCoreMock(mockedClass, roleName, constructorArgumentTypes, constructorArguments); } /** * Calculates a default role name for a mocked type. * @param mockedType * @return */ private static String defaultMockNameForType(Class mockedType) { return "mock" + Formatting.classShortName(mockedType); } }
It works for mocking both interfaces and classes (through CGLIB).
And here is a short example of usage (JDK5, because I use static imports):
public class TypeAccessFilterTest { @Test public void jmockBotNormalRequest() throws IOException, ServletException { // static imports Mock mockBotChecker = mock(BotChecker.class, new Class[0], new Object[0]); Mock mockFilterChain= mock(FilterChain.class); TypeAccessFilter taf= new TypeAccessFilter(); taf.setBotChecker((BotChecker) mockBotChecker.proxy()); mockFilterChain.expects(once()).method("doFilter") .with(isA(HttpServletRequest.class), isA(JSessionidBeautifierHttpResponseWrapper.class)); taf.doFilter(m_mockRequest, m_mockResponse, (FilterChain) mockFilterChain.proxy()); verifyAndRelease(); }
As far as I know the latest versions of EasyMock allow the same JUnit-free usage, which in my opinion is a great thing.