Извиняюсь за длинный вопрос ...
Для тестирования бизнес-логики, которая вызывает веб-службы Axis 1.4 в моих модульных тестах, в настоящее время я использую прокси-сервер Spring, который позволяет мне устанавливать исключения и моделироватьвозвращайте значения, как указано ниже.
Однако мне было интересно, есть ли более чистый способ сделать это:
В моем контексте приложения JUnit я ввел следующий совет:
<bean id="testProxy" class="appl.service.TestProxyImpl" />
<bean id="testAdvice" class="org.springframework.aop.support.DefaultIntroductionAdvisor">
<constructor-arg index="0" ref="testProxy"/>
<constructor-arg index="1" value="appl.service.ITestProxy"/>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="myAxisProxy"/>
<property name="interceptorNames" value="testAdvice"/>
</bean>
Класс TestProxyImpl выглядит следующим образом (дайте мне знать, если вам нужно увидеть интерфейс):
public class TestProxyImpl
extends DelegatingIntroductionInterceptor
implements ITestProxy {
private Map<String, Integer> calls = new HashMap<String, Integer>();
private Map<String, Throwable[]> exceptions = new HashMap<String, Throwable[]>();
private Map<String, Object> returnValues = new HashMap<String, Object>();
private Map<String, Object[]> lastParams = new HashMap<String, Object[]>();
public int getCalls(String methodName) {
Integer noCalls = calls.get(methodName);
if (noCalls == null) {
return 0;
}
return noCalls;
}
public void resetCalls() {
calls.clear();
returnValues.clear();
exceptions.clear();
lastParams.clear();
}
public void addExceptions(String method, Throwable... exceptions) {
this.exceptions.put(method, exceptions);
}
public void addReturnValue(String method, Object result) {
returnValues.put(method, result);
}
@SuppressWarnings("unchecked")
public <T> T getLastParameter(String method, Class<? extends T> paramClass) {
Object[] args = lastParams.get(method);
if (args != null) {
for (Object arg : args) {
if (arg != null) {
if (paramClass.isAssignableFrom(arg.getClass())) {
return (T)arg;
}
}
}
}
return null;
}
@Override
protected Object doProceed(MethodInvocation mi) throws Throwable {
String methodName = mi.getMethod().getName();
int noCalls;
synchronized (calls) {
noCalls = getCalls(methodName);
calls.put(methodName, noCalls + 1);
}
Object[] args = mi.getArguments();
synchronized (lastParams) {
lastParams.put(methodName, args);
}
if (exceptions.containsKey(methodName)) {
Throwable[] exceptionArray = exceptions.get(methodName);
if (exceptionArray != null) {
Throwable e = exceptionArray[noCalls % exceptionArray.length];
if (e != null) {
throw e;
}
}
}
if (returnValues.containsKey(methodName)) {
return returnValues.get(methodName);
}
return super.doProceed(mi);
}
}
, который позволяет мне использовать следующие модульные тесты:
protected void onSetUp() throws Exception {
super.onSetUp();
// testProxy is autowired into the unit test class
testProxy.resetCalls();
}
public void testSuccess() throws Exception {
// myBusinessObject is autowired into the unit test class
// myAxisProxy is injected into myBusinessObject in the spring context
// myBusinessObject calls myAxisProxy.myMethod(MyRequestObject) internally
myBusinessObject.doSomething();
// check that myAxisProxy has been called the correct times
// with the correct parameters
assertEquals(1, testProxy.getCalls("myMethod"));
assertEquals(
"foo",
testProxy.getLastParameter(
"myMethod",
MyRequestObject.class).getMyField());
}
public void testWithoutCallingProxy() throws Exception {
testProxy.addReturnValue("myMethod", createTestReturnValues());
myBusinessObject.doSomething();
// check that the response is as expected
}
public void testWithException() throws Exception {
testProxy.addException(
"myMethod",
AxisFault.makeFault(new ConnectException("test")),
null);
// this would check that the first call results in a ConnectException
// simulating a network error, but myBusinessObject retries
// and goes through to the service on the second call.
myBusinessObject.doSomething();
}
Я кратко рассмотрел EasyMock, но не был уверен, как мне удастся создать фиктивный объект, который перехватывает вызов и иногда возвращает исключение или указанные возвращаемые значения, но иногда использует правильный вызов, поэтомумне было интересно, есть ли у кого-нибудь идеи о том, как это упростить.
Обратите внимание, в идеале я бы хотел избежать необходимости перенастраивать свойства myBusinessObject
.
* 1.020 * Спасибо.
РЕДАКТИРОВАТЬ:
Я использую Spring 2.5, JUnit 3.8 и Axis 1.4
EDIT2:
Я использую этоподход к автоматизации интеграционных тестов, а не простые модульные тесты, так что любые предложения о том, как заменить решение, созданное вручную, чем-то на основе библиотеки, приветствуются.