4e321566dd6d3e0bb210c21658877e8f989eea16
[utils] / support / general / src / test / java / org / wamblee / test / ResettableMock.java
1 /**
2  * 
3  */
4 package org.wamblee.test;
5
6 import static org.mockito.Mockito.*;
7
8 import java.lang.reflect.InvocationHandler;
9 import java.lang.reflect.InvocationTargetException;
10 import java.lang.reflect.Method;
11 import java.lang.reflect.Proxy;
12
13 import net.sf.cglib.proxy.Enhancer;
14 import net.sf.cglib.proxy.MethodInterceptor;
15 import net.sf.cglib.proxy.MethodProxy;
16
17 /**
18  * Resettable mock is a utility to support reset functionality for mockito.
19  * 
20  * @author Erik Brakkee
21  * 
22  * @param <T>
23  */
24 public class ResettableMock<T> {
25
26     private static class MockitoInvocationHandler<T> implements
27             MethodInterceptor {
28
29         private Class<T> _class;
30         private T _mock;
31
32         public MockitoInvocationHandler(Class<T> aClass) {
33             _class = aClass;
34             _mock = mock(aClass);
35         }
36
37         public void reset() {
38             _mock = mock(_class);
39         }
40
41         public T getMock() {
42             return _mock;
43         }
44
45         @Override
46         public Object intercept(Object aProxy, Method aInterceptedMethod,
47                 Object[] aArgs, MethodProxy aMethodProxy) throws Throwable {
48             try {
49                 return aInterceptedMethod.invoke(_mock, aArgs);
50             } catch (InvocationTargetException e) {
51                 throw e.getCause();
52             }
53         }
54     }
55
56     /**
57      * Invocation handler that delegates to the current mockito mock and allows
58      * creation of a new mock.
59      */
60     private ResettableMock.MockitoInvocationHandler<T> _handler;
61
62     /**
63      * Proxy object to be passed to tested classes.
64      */
65     private T _proxy;
66
67     /**
68      * Constructs the resettable mock.
69      * 
70      * @param aType
71      *            Type to mock. Must be an interface or a non-final class with a 
72      *            default constructor.
73      */
74     public ResettableMock(Class<T> aType) {
75         if (!aType.isInterface()) {
76             throw new IllegalArgumentException("Class '" + aType.getName()
77                     + "' must be an interface");
78         }
79         _handler = new MockitoInvocationHandler(aType);
80         Enhancer enhancer = new Enhancer();
81         enhancer.setSuperclass(aType);
82         enhancer.setCallback(_handler);
83         _proxy = (T) enhancer.create();
84     }
85
86     /**
87      * Resets the mock effectively forgetting all previous interactions and
88      * verifications.
89      */
90     public void reset() {
91         _handler.reset();
92     }
93
94     /**
95      * Gets the current mock object to pass to mockito calls.
96      * 
97      * @return Mock object.
98      */
99     public T getMock() {
100         return _handler.getMock();
101     }
102
103     /**
104      * Returns the proxy that your tested classes will used.
105      * 
106      * @return Proxy object.
107      */
108     public T getProxy() {
109         return _proxy;
110     }
111
112 }