+/**
+ *
+ */
+package org.wamblee.test;
+
+import static org.mockito.Mockito.*;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * 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;
+ }
+
+}
\ No newline at end of file