如何为Spring的WebServiceTemplate创建一个模拟对象?

问题描述:

我有一个呼叫到现有的Web服务的类。我的课程正确处理了有效的结果以及由Web服务生成的错误字符串。对Web服务的基本调用看起来像这样(尽管这是简化的)。如何为Spring的WebServiceTemplate创建一个模拟对象?

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?

迈克尔答案非常接近,但这里是有效的例子。

我已经在单元测试中使用Mockito,所以我对库很熟悉。然而,与我以前使用Mockito的经历不同,简单地嘲笑返回结果并没有帮助。我需要做两件事来测试所有的用例:

  1. 修改存储在StreamResult中的值。
  2. 抛出SoapFaultClientException。

首先,我需要认识到,我不能用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; 
} 

更多的代码可能需要这两种使用情况,但他们为我的目的工作。

实际上我不知道是否存在预配置的模拟对象,但我怀疑是否配置了所有的“失败条件”,因此您可以为您的JUnit测试创建一个特殊的Spring ApplicationContext替代或使用模拟框架,它并不难:-)

我使用的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; 
    } 
} 
+0

Mockito +1。 – CoverosGene 2009-04-27 20:06:30