001: /* MockUtilsBean.java
002: *
003: * DDSteps - Data Driven JUnit Test Steps
004: * Copyright (C) 2005 Jayway AB
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License version 2.1 as published by the Free Software Foundation.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, visit
017: * http://www.opensource.org/licenses/lgpl-license.php
018: */
019: package org.ddsteps.mock;
020:
021: import java.lang.reflect.Field;
022: import java.lang.reflect.Method;
023: import java.util.Collection;
024: import java.util.HashSet;
025: import java.util.Iterator;
026: import java.util.LinkedList;
027: import java.util.Set;
028:
029: import org.apache.commons.collections.CollectionUtils;
030: import org.apache.commons.logging.Log;
031: import org.apache.commons.logging.LogFactory;
032: import org.easymock.MockControl;
033: import org.easymock.classextension.MockClassControl;
034:
035: /**
036: * Implements MockUtils.
037: *
038: * @author ct26
039: */
040: class MockUtilsBean {
041: private static final Log LOG = LogFactory
042: .getLog(MockUtilsBean.class);
043:
044: protected final ReflectionUtils reflectionUtils;
045:
046: protected final MockableMethodPredicate mockableMethodPredicate;
047:
048: /**
049: * No-args.
050: */
051: public MockUtilsBean() {
052: this .reflectionUtils = new ReflectionUtilsBean();
053: this .mockableMethodPredicate = new MockableMethodPredicate(
054: reflectionUtils);
055: }
056:
057: /**
058: * Dependency injection constructor.
059: *
060: * @param reflectionUtilsBean
061: * @param mockableMethodPredicate
062: */
063: public MockUtilsBean(ReflectionUtilsBean reflectionUtilsBean,
064: MockableMethodPredicate mockableMethodPredicate) {
065: this .reflectionUtils = reflectionUtilsBean;
066: this .mockableMethodPredicate = mockableMethodPredicate;
067:
068: }
069:
070: /**
071: * Get list of not-null MockControl fields. Makes the fields accessible by
072: * force.
073: *
074: * @param testCase
075: * The object to look in.
076: * @return (@link Collection) of (@link MockControl), never null.
077: */
078: protected Collection findMockControlsInFields(Object testCase) {
079: LinkedList mockControls = new LinkedList();
080: Class clazz = testCase.getClass();
081:
082: // Seek upwards, stop and don't look in Object
083: while (clazz != Object.class) {
084: // All fields are returned from all classes
085: Field[] fields = clazz.getDeclaredFields();
086:
087: // check if it is a mock
088: for (int i = 0; i < fields.length; i++) {
089: Field field = fields[i];
090:
091: if (MockControl.class.isAssignableFrom(field.getType())) {
092:
093: // Force access to this field.
094: // This only works when security is OFF, and it usually is.
095: field.setAccessible(true);
096:
097: try {
098: // Now get it
099: Object control = field.get(testCase);
100:
101: // Skip null mockcontrols
102: if (control != null) {
103: mockControls.addLast(control);
104:
105: if (LOG.isDebugEnabled()) {
106: LOG
107: .debug("Processing MockControl field... ( Field = "
108: + field.getName()
109: + " )");
110: }
111:
112: } else {
113: LOG
114: .warn("MockControl field was null. (Field = "
115: + field.getName() + ")");
116: }
117:
118: } catch (Exception e) {
119: throw new RuntimeException(
120: "Exception accessing fields", e);
121: }
122: }
123:
124: }
125:
126: clazz = clazz.getSuperclass();
127: }
128:
129: return mockControls;
130: }
131:
132: /**
133: * @param clazz
134: * @return MockControl for the mock
135: * @see MockUtils#createAbstractStrictClassControl(Class)
136: */
137: public MockControl createAbstractStrictClassControl(
138: final Class clazz) {
139:
140: // abstract methods
141: HashSet abstractMethods = new HashSet();
142:
143: // Add interface methods (abstract)
144: abstractMethods.addAll(reflectionUtils
145: .findInterfaceMethods(clazz));
146:
147: // Add abstract methods
148: abstractMethods.addAll(reflectionUtils
149: .findAllAbstractMethods(clazz));
150:
151: // Remove any implemented methods
152: abstractMethods.removeAll(reflectionUtils
153: .findAllImplementedMethods(clazz));
154:
155: MockControl control = createMockClassControl(abstractMethods,
156: clazz);
157:
158: return control;
159:
160: }
161:
162: /**
163: * @param clazz
164: * @return Not null.
165: * @see MockUtils#createFocusedStrictClassControl(Class)
166: */
167: public MockControl createFocusedStrictClassControl(final Class clazz) {
168:
169: // abstract methods
170: HashSet mockedMethods = new HashSet();
171:
172: mockedMethods.addAll(reflectionUtils
173: .findInterfaceMethods(clazz));
174:
175: // Add abstract methods
176: mockedMethods.addAll(reflectionUtils
177: .findAllAbstractMethods(clazz));
178:
179: // Add all super methods
180: mockedMethods.addAll(reflectionUtils
181: .findAllMethodsInSuperclasses(clazz));
182:
183: // Remove any locally implemented methods
184: mockedMethods.addAll(reflectionUtils
185: .findLocalImplementedMethods(clazz));
186:
187: MockControl control = createMockClassControl(mockedMethods,
188: clazz);
189:
190: return control;
191:
192: }
193:
194: /**
195: * Creates mock where ALL METHODS (implemented or not) are mocked EXCEPT for
196: * the method whose name you supply. This is the kind of mock you use to
197: * test just one method in your class at a time.<br>
198: * If there is more than one method with the same name, the first one found
199: * gets mocked.<br>
200: * TODO: Overload method with one that takes params to exacly specify the
201: * method to leave unmocked.
202: *
203: * @param clazz
204: * The class
205: * @param methodName
206: * The method name.
207: * @return MockControl, never null.
208: * @throws NoSuchMethodException
209: * Thrown if the method cannot be found.
210: */
211: public MockControl createMethodFocusedStrictClassControl(
212: final Class clazz, String methodName)
213: throws NoSuchMethodException {
214:
215: // abstract methods
216: HashSet mockedMethods = new HashSet();
217:
218: mockedMethods.addAll(reflectionUtils
219: .findInterfaceMethods(clazz));
220:
221: // Add abstract methods
222: mockedMethods.addAll(reflectionUtils
223: .findAllAbstractMethods(clazz));
224:
225: // Add all methods methods
226: mockedMethods.addAll(reflectionUtils.findAllMethods(clazz));
227:
228: // remove the one method not to mock
229: mockedMethods.remove(reflectionUtils.findMethodByName(clazz,
230: methodName));
231:
232: // Create mock control
233: MockControl control = createMockClassControl(mockedMethods,
234: clazz);
235:
236: return control;
237:
238: }
239:
240: /**
241: * @param methodsToMock
242: * @param clazz
243: * @return The MockControl
244: */
245: protected MockControl createMockClassControl(Set methodsToMock,
246: final Class clazz) {
247:
248: // Filter out un-mockable methods
249: CollectionUtils.filter(methodsToMock, mockableMethodPredicate);
250:
251: Method[] methodArray = (Method[]) methodsToMock
252: .toArray(new Method[methodsToMock.size()]);
253:
254: // ok, mock all found methods
255: MockControl control = MockClassControl.createStrictControl(
256: clazz, methodArray);
257:
258: return control;
259: }
260:
261: /**
262: * Call replay() on all MockControl fields. Getters are NOT used! Looks for
263: * fields in superclasses too.
264: *
265: * @param testCase
266: * The testcase to search.
267: * @return The number of mock controls processed.
268: * @see MockUtils#replay(Object)
269: */
270: public int replay(Object testCase) {
271:
272: // Contract says no nulls in collection
273: Collection mockControls = findMockControlsInFields(testCase);
274:
275: // OK, now call all found mock controls
276: for (Iterator iter = mockControls.iterator(); iter.hasNext();) {
277: MockControl control = (MockControl) iter.next();
278: control.replay();
279: }
280:
281: return mockControls.size();
282:
283: }
284:
285: /**
286: * Call verify() on all MockControl fields. Getters are NOT used! Looks for
287: * fields in superclasses too.s
288: *
289: * @param testCase
290: * The testcase to search
291: * @return The number of MockControls processed.
292: * @see MockUtils#verify(Object)
293: */
294: public int verify(Object testCase) {
295:
296: Collection mockControls = findMockControlsInFields(testCase);
297:
298: // OK, now call all found mock controls
299: for (Iterator iter = mockControls.iterator(); iter.hasNext();) {
300: MockControl control = (MockControl) iter.next();
301: control.verify();
302: }
303:
304: return mockControls.size();
305:
306: }
307:
308: }
|