Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2008, Unitils.org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.unitils.easymock;
import org.easymock.classextension.internal.MocksClassControl;
import org.easymock.internal.MocksControl;
import org.easymock.internal.ReplayState;
import org.unitils.core.Module;
import org.unitils.core.TestListener;
import org.unitils.core.UnitilsException;
import org.unitils.easymock.annotation.AfterCreateMock;
import org.unitils.easymock.annotation.Mock;
import org.unitils.easymock.annotation.RegularMock;
import org.unitils.easymock.util.*;
import org.unitils.reflectionassert.ReflectionComparatorMode;
import org.unitils.util.PropertyUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import static org.easymock.internal.MocksControl.MockType.DEFAULT;
import static org.easymock.internal.MocksControl.MockType.NICE;
import static org.unitils.reflectionassert.ReflectionComparatorMode.*;
import static org.unitils.util.AnnotationUtils.getFieldsAnnotatedWith;
import static org.unitils.util.AnnotationUtils.getMethodsAnnotatedWith;
import static org.unitils.util.ModuleUtils.getAnnotationPropertyDefaults;
import static org.unitils.util.ModuleUtils.getEnumValueReplaceDefault;
import static org.unitils.util.ReflectionUtils.invokeMethod;
import static org.unitils.util.ReflectionUtils.setFieldValue;
/**
* Module for testing with mock objects using EasyMock.
*
* Mock creation is simplified by automatically inserting EasyMock generated mocks for fields annotated with the
* {@link Mock} annotation.
*
* All methods annotated with {@link AfterCreateMock} will be called when a mock object was created. This provides
* you with a hook method for custom handling of the mock (e.g. adding the mocks to a service locator repository).
* A method can only be called if it has following signature void myMethod(Object mock, String name, Class type).
*
* Mocks can also be created explicitly
* todo javadoc
*
* Switching to the replay state and verifying expectations of all mocks (including the mocks created with
* the createMock() method can be done by calling
* the {@link #replay()} and {@link #verify()} methods.
*
* @author Filip Neven
* @author Tim Ducheyne
*/
public class EasyMockModule implements Module {
/* Property key for configuring whether verify() is automatically called on every mock object after each test method execution */
public static final String PROPKEY_AUTO_VERIFY_AFTER_TEST_ENABLED = "EasyMockModule.autoVerifyAfterTest.enabled";
/* All created mocks controls */
private List mocksControls;
/* Map holding the default configuration of the mock annotations */
private Map, Map> defaultAnnotationPropertyValues;
/* Indicates whether verify() is automatically called on every mock object after each test method execution */
private boolean autoVerifyAfterTestEnabled;
/**
* Initializes the module
*/
@SuppressWarnings("unchecked")
public void init(Properties configuration) {
mocksControls = new ArrayList();
defaultAnnotationPropertyValues = getAnnotationPropertyDefaults(EasyMockModule.class, configuration, RegularMock.class, Mock.class);
autoVerifyAfterTestEnabled = PropertyUtils.getBoolean(PROPKEY_AUTO_VERIFY_AFTER_TEST_ENABLED, configuration);
}
/**
* No after initialization needed for this module
*/
public void afterInit() {
}
/**
* Creates the listener for plugging in the behavior of this module into the test runs.
*
* @return the listener
*/
public TestListener getTestListener() {
return new EasyMockTestListener();
}
/**
* Creates an EasyMock mock object of the given type.
*
* An instance of the mock control is stored, so that it can be set to the replay/verify state when
* {@link #replay()} or {@link #verify()} is called.
*
* @param the type of the mock
* @param mockType the class type for the mock, not null
* @param invocationOrder the order setting, not null
* @param calls the calls setting, not null
* @return a mock for the given class or interface, not null
*/
public T createRegularMock(Class mockType, InvocationOrder invocationOrder, Calls calls) {
// Get anotation arguments and replace default values if needed
invocationOrder = getEnumValueReplaceDefault(RegularMock.class, "invocationOrder", invocationOrder,
defaultAnnotationPropertyValues);
calls = getEnumValueReplaceDefault(RegularMock.class, "calls", calls, defaultAnnotationPropertyValues);
MocksControl mocksControl;
if (Calls.LENIENT == calls) {
mocksControl = new MocksClassControl(NICE);
} else {
mocksControl = new MocksClassControl(DEFAULT);
}
// Check order
if (InvocationOrder.STRICT == invocationOrder) {
mocksControl.checkOrder(true);
}
mocksControls.add(mocksControl);
return mocksControl.createMock(mockType);
}
/**
* todo javadoc
*
* Creates an EasyMock mock instance of the given type (class/interface). The type of mock is determined
* as follows:
*
* If returns is set to LENIENT, a nice mock is created, else a default mock is created
* If arguments is lenient a lenient control is create, else an EasyMock control is created
* If order is set to strict, invocation order checking is enabled
*
* @param the type of the mock
* @param mockType the type of the mock, not null
* @param invocationOrder the order setting, not null
* @param calls the calls setting, not null
* @param order todo
* @param dates todo
* @param defaults todo
* @return a mockcontrol for the given class or interface, not null
*/
public T createMock(Class mockType, InvocationOrder invocationOrder, Calls calls, Order order, Dates dates, Defaults defaults) {
// Get anotation arguments and replace default values if needed
invocationOrder = getEnumValueReplaceDefault(Mock.class, "invocationOrder", invocationOrder, defaultAnnotationPropertyValues);
calls = getEnumValueReplaceDefault(Mock.class, "calls", calls, defaultAnnotationPropertyValues);
order = getEnumValueReplaceDefault(Mock.class, "order", order, defaultAnnotationPropertyValues);
dates = getEnumValueReplaceDefault(Mock.class, "dates", dates, defaultAnnotationPropertyValues);
defaults = getEnumValueReplaceDefault(Mock.class, "defaults", defaults, defaultAnnotationPropertyValues);
List comparatorModes = new ArrayList();
if (Order.LENIENT == order) {
comparatorModes.add(LENIENT_ORDER);
}
if (Dates.LENIENT == dates) {
comparatorModes.add(LENIENT_DATES);
}
if (Defaults.IGNORE_DEFAULTS == defaults) {
comparatorModes.add(IGNORE_DEFAULTS);
}
LenientMocksControl mocksControl;
if (Calls.LENIENT == calls) {
mocksControl = new LenientMocksControl(NICE, comparatorModes.toArray(new ReflectionComparatorMode[0]));
} else {
mocksControl = new LenientMocksControl(DEFAULT, comparatorModes.toArray(new ReflectionComparatorMode[0]));
}
// Check order
if (InvocationOrder.STRICT == invocationOrder) {
mocksControl.checkOrder(true);
}
mocksControls.add(mocksControl);
return mocksControl.createMock(mockType);
}
/**
* Replays all mock controls.
*/
public void replay() {
for (MocksControl mocksControl : mocksControls) {
mocksControl.replay();
}
}
/**
* Resets all mock controls.
*/
public void reset() {
for (MocksControl mocksControl : mocksControls) {
mocksControl.reset();
}
}
/**
* This method makes sure {@link org.easymock.internal.MocksControl#verify} method is called for every mock mock object
* that was injected to a field annotated with {@link Mock}, or directly created by calling
* {@link #createRegularMock(Class, InvocationOrder, Calls)} or
* {@link #createMock(Class, InvocationOrder, Calls, Order, Dates, Defaults)}.
*
* If there are mocks that weren't already switched to the replay state using {@link MocksControl#replay()}} or by
* calling {@link org.unitils.easymock.EasyMockUnitils#replay()}, this method is called first.
*/
public void verify() {
for (MocksControl mocksControl : mocksControls) {
if (!(mocksControl.getState() instanceof ReplayState)) {
mocksControl.replay();
}
mocksControl.verify();
}
}
/**
* Creates and sets a mock for all {@link RegularMock} annotated fields.
*
* The
* todo javadoc
* method is called for creating the mocks. Ones the mock is created, all methods annotated with {@link AfterCreateMock} will be called passing the created mock.
*
* @param testObject the test, not null
*/
protected void createAndInjectRegularMocksIntoTest(Object testObject) {
Set mockFields = getFieldsAnnotatedWith(testObject.getClass(), RegularMock.class);
for (Field mockField : mockFields) {
Class> mockType = mockField.getType();
RegularMock regularMockAnnotation = mockField.getAnnotation(RegularMock.class);
Object mockObject = createRegularMock(mockType, regularMockAnnotation.invocationOrder(), regularMockAnnotation.calls());
setFieldValue(testObject, mockField, mockObject);
callAfterCreateMockMethods(testObject, mockObject, mockField.getName(), mockType);
}
}
//todo javadoc
protected void createAndInjectMocksIntoTest(Object testObject) {
Set mockFields = getFieldsAnnotatedWith(testObject.getClass(), Mock.class);
for (Field mockField : mockFields) {
Class> mockType = mockField.getType();
Mock mockAnnotation = mockField.getAnnotation(Mock.class);
Object mockObject = createMock(mockType, mockAnnotation.invocationOrder(), mockAnnotation.calls(), mockAnnotation.order(), mockAnnotation.dates(), mockAnnotation.defaults());
setFieldValue(testObject, mockField, mockObject);
callAfterCreateMockMethods(testObject, mockObject, mockField.getName(), mockType);
}
}
/**
* Calls all {@link AfterCreateMock} annotated methods on the test, passing the given mock.
* These annotated methods must have following signature void myMethod(Object mock, String name, Class type).
* If this is not the case, a runtime exception is called.
*
* @param testObject the test, not null
* @param mockObject the mock, not null
* @param name the field(=mock) name, not null
* @param type the field(=mock) type
*/
protected void callAfterCreateMockMethods(Object testObject, Object mockObject, String name, Class> type) {
Set methods = getMethodsAnnotatedWith(testObject.getClass(), AfterCreateMock.class);
for (Method method : methods) {
try {
invokeMethod(testObject, method, mockObject, name, type);
} catch (InvocationTargetException e) {
throw new UnitilsException("An exception occurred while invoking an after create mock method.", e);
} catch (Exception e) {
throw new UnitilsException("Unable to invoke after create mock method. Ensure that this method has following signature: " +
"void myMethod(Object mock, String name, Class type)", e);
}
}
}
/**
* Test listener that handles the mock creation and injection.
*/
protected class EasyMockTestListener extends TestListener {
/**
* Before the test is executed this calls {@link EasyMockModule#createAndInjectRegularMocksIntoTest(Object)} to
* create and inject all mocks on the class.
*/
@Override
public void beforeTestSetUp(Object testObject, Method testMethod) {
// Clear all previously created mocks controls
mocksControls.clear();
createAndInjectRegularMocksIntoTest(testObject);
createAndInjectMocksIntoTest(testObject);
}
/**
* After each test is executed this calls {@link EasyMockModule#verify()} to verify the recorded behavior
* of all created mocks.
*/
@Override
public void afterTestMethod(Object testObject, Method testMethod, Throwable throwable) {
if (autoVerifyAfterTestEnabled && throwable == null) {
verify();
}
}
}
}