import static org.mockito.Mockito.*;
import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.proxy.MethodInterceptor;
+import net.sf.cglib.proxy.MethodProxy;
+
/**
- * Resettable mock is a utility to support reset functionality for mockito.
+ * Resettable mock is a utility to support reset functionality for mockito.
+ *
* @author Erik Brakkee
- *
+ *
* @param <T>
*/
public class ResettableMock<T> {
- private static class MockitoInvocationHandler<T> implements
- InvocationHandler {
-
- private Class<T> _class;
- private T _mock;
-
- public MockitoInvocationHandler(Class<T> aClass) {
- _class = aClass;
- _mock = mock(aClass);
- }
-
- public void reset() {
- _mock = mock(_class);
- }
-
- public T getMock() {
- return _mock;
- }
-
- @Override
- public Object invoke(Object aProxy, Method aMethod, Object[] aArgs)
- throws Throwable {
- return aMethod.invoke(_mock, aArgs);
- }
- }
-
- /**
- * Invocation handler that delegates to the current mockito mock and allows
- * creation of a new mock.
- */
- private ResettableMock.MockitoInvocationHandler<T> _handler;
-
- /**
- * Proxy object to be passed to tested classes.
- */
- private T _proxy;
-
- /**
- * Constructs the resettable mock.
- * @param aType Type to mock. Must be an interface type.
- */
- public ResettableMock(Class<T> aType) {
- if ( !aType.isInterface()) {
- throw new IllegalArgumentException("Class '" + aType.getName() + "' must be an interface");
- }
- _handler = new MockitoInvocationHandler(aType);
- _proxy = (T) Proxy.newProxyInstance(aType.getClassLoader(),
- new Class[] { aType }, _handler);
- }
-
- /**
- * Resets the mock effectively forgetting all previous interactions and verifications.
- */
- public void reset() {
- _handler.reset();
- }
-
- /**
- * Gets the current mock object to pass to mockito calls.
- *
- * @return Mock object.
- */
- public T getMock() {
- return _handler.getMock();
- }
-
- /**
- * Returns the proxy that your tested classes will used.
- *
- * @return Proxy object.
- */
- public T getProxy() {
- return _proxy;
- }
+ private static class MockitoInvocationHandler<T> implements
+ MethodInterceptor {
+
+ private Class<T> _class;
+ private T _mock;
+
+ public MockitoInvocationHandler(Class<T> aClass) {
+ _class = aClass;
+ _mock = mock(aClass);
+ }
+
+ public void reset() {
+ _mock = mock(_class);
+ }
+
+ public T getMock() {
+ return _mock;
+ }
+
+ @Override
+ public Object intercept(Object aProxy, Method aInterceptedMethod,
+ Object[] aArgs, MethodProxy aMethodProxy) throws Throwable {
+ try {
+ return aInterceptedMethod.invoke(_mock, aArgs);
+ } catch (InvocationTargetException e) {
+ throw e.getCause();
+ }
+ }
+ }
+
+ /**
+ * Invocation handler that delegates to the current mockito mock and allows
+ * creation of a new mock.
+ */
+ private ResettableMock.MockitoInvocationHandler<T> _handler;
+
+ /**
+ * Proxy object to be passed to tested classes.
+ */
+ private T _proxy;
+
+ /**
+ * Constructs the resettable mock.
+ *
+ * @param aType
+ * Type to mock. Must be an interface or a non-final class with a
+ * default constructor.
+ */
+ public ResettableMock(Class<T> aType) {
+ if (!aType.isInterface()) {
+ throw new IllegalArgumentException("Class '" + aType.getName()
+ + "' must be an interface");
+ }
+ _handler = new MockitoInvocationHandler(aType);
+ Enhancer enhancer = new Enhancer();
+ enhancer.setSuperclass(aType);
+ enhancer.setCallback(_handler);
+ _proxy = (T) enhancer.create();
+ }
+
+ /**
+ * Resets the mock effectively forgetting all previous interactions and
+ * verifications.
+ */
+ public void reset() {
+ _handler.reset();
+ }
+
+ /**
+ * Gets the current mock object to pass to mockito calls.
+ *
+ * @return Mock object.
+ */
+ public T getMock() {
+ return _handler.getMock();
+ }
+
+ /**
+ * Returns the proxy that your tested classes will used.
+ *
+ * @return Proxy object.
+ */
+ public T getProxy() {
+ return _proxy;
+ }
}
\ No newline at end of file