resettablemock now also works with concrete classes with a default
authorErik Brakkee <erik@brakkee.org>
Wed, 16 Jul 2008 10:13:22 +0000 (10:13 +0000)
committerErik Brakkee <erik@brakkee.org>
Wed, 16 Jul 2008 10:13:22 +0000 (10:13 +0000)
constructor. Non-default constructors cannot be supported since that
would require support from mockito as well (spy() functionality).

support/general/src/test/java/org/wamblee/test/ResettableMock.java

index 47cc67474774cc53ebf940822d765ab80595d047..4e321566dd6d3e0bb210c21658877e8f989eea16 100644 (file)
@@ -6,90 +6,107 @@ package org.wamblee.test;
 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