我有一个调用现有Web服务的类。我的类正确处理有效的结果以及Web服务生成的错误字符串。对Web服务的基本调用看起来像这样(虽然这是简化的)。
public String callWebService(final String inputXml)
{
String result = null;
try
{
StreamSource input = new StreamSource(new StringReader(inputXml));
StringWriter output = new StringWriter();
_webServiceTemplate.sendSourceAndReceiveToResult(_serviceUri, input, new StreamResult(output));
result = output.toString();
}
catch (SoapFaultClientException ex)
{
result = ex.getFaultStringOrReason();
}
return result;
}
现在我需要创建一些测试所有成功和失败条件的单元测试。它无法调用实际的Web服务,所以我希望有一些模拟对象可用于Spring-WS的客户端。有没有人知道可用于WebServiceTemplate或任何相关类的模拟对象?我是否应该尝试编写自己的类并修改我的类以使用WebServiceOperations接口而不是WebServiceTemplate?
答案 0 :(得分:7)
我已经使用Mockito进行单元测试了,所以我对图书馆很熟悉。然而,与我之前对Mockito的经历不同,简单地模拟返回结果并没有帮助。我需要做两件事来测试所有用例:
首先,我需要意识到我不能用Mockito模拟WebServiceTemplate,因为它是一个具体的类(如果这是必不可少的,你需要使用EasyMock)。幸运的是,对Web服务的调用sendSourceAndReceiveToResult是WebServiceOperations接口的一部分。这需要更改我的代码以期望WebServiceOperations与WebServiceTemplate。
以下代码支持在StreamResult参数中返回结果的第一个用例:
private WebServiceOperations getMockWebServiceOperations(final String resultXml)
{
WebServiceOperations mockObj = Mockito.mock(WebServiceOperations.class);
doAnswer(new Answer()
{
public Object answer(InvocationOnMock invocation)
{
try
{
Object[] args = invocation.getArguments();
StreamResult result = (StreamResult)args[2];
Writer output = result.getWriter();
output.write(resultXml);
}
catch (IOException e)
{
e.printStackTrace();
}
return null;
}
}).when(mockObj).sendSourceAndReceiveToResult(anyString(), any(StreamSource.class), any(StreamResult.class));
return mockObj;
}
对第二个用例的支持是类似的,但需要抛出异常。以下代码创建一个包含faultString的SoapFaultClientException。 faultCode由我正在测试的代码使用,它处理Web服务请求:
private WebServiceOperations getMockWebServiceOperations(final String faultString)
{
WebServiceOperations mockObj = Mockito.mock(WebServiceOperations.class);
SoapFault soapFault = Mockito.mock(SoapFault.class);
when(soapFault.getFaultStringOrReason()).thenReturn(faultString);
SoapBody soapBody = Mockito.mock(SoapBody.class);
when(soapBody.getFault()).thenReturn(soapFault);
SoapMessage soapMsg = Mockito.mock(SoapMessage.class);
when(soapMsg.getSoapBody()).thenReturn(soapBody);
doThrow(new SoapFaultClientException(soapMsg)).when(mockObj).sendSourceAndReceiveToResult(anyString(), any(StreamSource.class), any(StreamResult.class));
return mockObj;
}
这两个用例可能需要更多代码,但它们可以用于我的目的。
答案 1 :(得分:5)
实际上我不知道是否存在预先配置的Mock对象,但我怀疑是否已经为所有“失败条件”配置了,因此您可以使用替换为您的JUnit Test创建一个特殊的Spring ApplicationContext或使用mock框架,并不难: - )
我使用Mockito模拟框架作为示例(并快速输入),但EasyMock或您首选的模拟框架也应该这样做
package org.foo.bar
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
public class WebserviceTemplateMockTest {
private WhateverTheInterfaceIs webServiceTemplate;
private TestClassInterface testClass;
private final String inputXml = "bar";
@Test
public void testClient(){
//
assertTrue("foo".equals(testClass.callWebService(inputXml));
}
/**
* Create Webservice Mock.
*/
@Before
public void createMock() {
// create Mock
webServiceTemplate = mock(WhateverTheInterfaceIs.class);
// like inputXml you need to create testData for Uri etc.
// 'result' should be the needed result data to produce the
// real result of testClass.callWebService(...)
when(webServiceTemplate.sendSourceAndReceiveToResult(Uri, inputXml, new StreamResult(output))).thenReturn(result);
// or return other things, e.g.
// .thenThrow(new FoobarException());
// see mockito documentation for more possibilities
// Setup Testclass
TestClassImpl temp = new TestClassImpl();
temp.setWebServiceTemplate(generatedClient);
testClass = temp;
}
}