【发布时间】:2011-09-07 10:41:29
【问题描述】:
为这个冗长的问题道歉......
为了测试在我的单元测试中调用 Axis 1.4 Web 服务的业务逻辑,我目前正在使用 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 的属性。
谢谢。
编辑:
我正在使用 Spring 2.5、JUnit 3.8 和 Axis 1.4
EDIT2:
我正在使用这种方法来自动化集成测试,而不是简单的单元测试,所以我非常欢迎关于如何用基于库的东西替换手工解决方案的任何建议。
【问题讨论】:
标签: java spring exception junit axis