01: /*
02: * Copyright 2006-2007 The Kuali Foundation.
03: *
04: * Licensed under the Educational Community License, Version 1.0 (the "License");
05: * you may not use this file except in compliance with the License.
06: * You may obtain a copy of the License at
07: *
08: * http://www.opensource.org/licenses/ecl1.php
09: *
10: * Unless required by applicable law or agreed to in writing, software
11: * distributed under the License is distributed on an "AS IS" BASIS,
12: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13: * See the License for the specific language governing permissions and
14: * limitations under the License.
15: */
16: package org.kuali.test;
17:
18: import java.lang.reflect.InvocationHandler;
19: import java.lang.reflect.Method;
20: import java.lang.reflect.Proxy;
21: import java.util.HashMap;
22:
23: import junit.framework.AssertionFailedError;
24:
25: /**
26: * This class implements a mock object for any service, using a dynamic proxy. It returns results for specific methods and
27: * arguments, and can also relay unspecified methods or arguments to a fallback service. Note that this proxy does not do Spring
28: * things like AOP transactions, altho the fallback service may.
29: */
30: public class MockService implements InvocationHandler {
31:
32: private final HashMap<String, MockMethod> nameToMockMethodMap = new HashMap<String, MockMethod>();
33: private final Object noMethodFallback;
34:
35: private MockService(MockMethod[] mockMethods,
36: Object noMethodFallback) {
37: this .noMethodFallback = noMethodFallback;
38: for (MockMethod m : mockMethods) {
39: nameToMockMethodMap.put(m.getName(), m);
40: }
41: }
42:
43: /**
44: * Returns the result associated with the given method and list of arguments. If there is no mock method, invokes the given
45: * method on the noMethodFallback Object. If the noMethodFallback Object is null, throws a
46: * {@link junit.framework.AssertionFailedError}.
47: *
48: * @see java.lang.reflect.InvocationHandler#invoke
49: */
50: public Object invoke(Object proxy, Method method, Object[] args)
51: throws Throwable {
52: String name = method.getName();
53: if (nameToMockMethodMap.containsKey(name)) {
54: MockMethod m = nameToMockMethodMap.get(name);
55: return m.invoke(proxy, method, args);
56: }
57: if (noMethodFallback == null) {
58: throw new AssertionFailedError("no mock method " + name);
59: }
60: return method.invoke(noMethodFallback, args);
61: }
62:
63: /**
64: * Creates a dynamic proxy with the given mock methods.
65: *
66: * @param iface the interface to proxy
67: * @param mockMethods the methods to mock
68: * @param noMethodFallback the Object to use when there is no mock method for the invoked method, or null if a
69: * {@link junit.framework.AssertionFailedError} should be thrown in this case instead.
70: * @return a dynamic proxy implementing the given interface
71: */
72: public static <I> I createProxy(Class<I> iface,
73: MockMethod[] mockMethods, Object noMethodFallback) {
74: // noinspection unchecked
75: return (I) Proxy.newProxyInstance(iface.getClassLoader(),
76: new Class[] { iface }, new MockService(mockMethods,
77: noMethodFallback));
78: }
79:
80: /**
81: * Creates a dynamic proxy with a single mock method that has a single result. Invocations of other methods or arguments will
82: * throw a {@link junit.framework.AssertionFailedError}.
83: *
84: * @param iface the interface to proxy
85: * @param methodName the name of the method to mock
86: * @param args the arguments to expect for the named method
87: * @param result the result to return from the named method
88: * @return a dynamic proxy implementing the given interface
89: */
90: public static <I> I createProxy(Class<I> iface, String methodName,
91: Object[] args, Object result) {
92: MockMethod mockMethod = new MockMethod(methodName, null);
93: mockMethod.setResult(result, args);
94: return createProxy(iface, new MockMethod[] { mockMethod }, null);
95: }
96: }
|