【问题标题】:How do I create a mock object for Spring's WebServiceTemplate?如何为 Spring 的 WebServiceTemplate 创建一个模拟对象?
【发布时间】:2009-04-27 19:16:22
【问题描述】:

我有一个调用现有网络服务的类。我的课程正确处理了有效结果以及 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?

【问题讨论】:

    标签: java mocking spring-ws


    【解决方案1】:

    Michael 的答案非常接近,但这是一个有效的例子。

    我已经在我的单元测试中使用了 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;
    }
    

    这两个用例可能需要更多代码,但它们适用于我的目的。

    【讨论】:

      【解决方案2】:

      实际上我不知道是否存在预配置的 Mock 对象,但我怀疑是否已为您的所有“失败条件”配置,因此您可以为您的 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;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-23
        • 1970-01-01
        • 2017-04-07
        • 2021-01-03
        • 1970-01-01
        • 1970-01-01
        • 2020-02-16
        • 2011-12-09
        相关资源
        最近更新 更多