【问题标题】:Strategies to mock a webservice模拟 Web 服务的策略
【发布时间】:2009-04-30 05:44:13
【问题描述】:

我正在实现一个使用 Web 服务的客户端。我想减少依赖并决定模拟网络服务。
我使用mockito,与 EasyMock 相比,它的优势在于能够模拟类,而不仅仅是接口。但这不是重点。

在我的测试中,我得到了这个代码:

// Mock the required objects
Document mDocument = mock(Document.class);
Element mRootElement = mock(Element.class);
Element mGeonameElement = mock(Element.class);
Element mLatElement = mock(Element.class);
Element mLonElement = mock(Element.class);

// record their behavior
when(mDocument.getRootElement()).thenReturn(mRootElement);
when(mRootElement.getChild("geoname")).thenReturn(mGeonameElement);
when(mGeonameElement.getChild("lat")).thenReturn(mLatElement);
when(mGeonameElement.getChild("lon")).thenReturn(mLonElement);
// A_LOCATION_BEAN is a simple pojo for lat & lon, don't care about it!
when(mLatElement.getText()).thenReturn(
    Float.toString(A_LOCATION_BEAN.getLat()));
when(mLonElement.getText()).thenReturn(
    Float.toString(A_LOCATION_BEAN.getLon()));

// let it work!
GeoLocationFetcher geoLocationFetcher = GeoLocationFetcher
    .getInstance();
LocationBean locationBean = geoLocationFetcher
    .extractGeoLocationFromXml(mDocument);

// verify their behavior
verify(mDocument).getRootElement();
verify(mRootElement).getChild("geoname");
verify(mGeonameElement).getChild("lat");
verify(mGeonameElement).getChild("lon");
verify(mLatElement).getText();
verify(mLonElement).getText();

assertEquals(A_LOCATION_BEAN, locationBean);

我的代码显示的是我对消费对象进行了“微测试”。就像我会在我的测试中实现我的生产代码一样。结果 xml 的一个示例是 London on GeoNames。 在我看来,它太细了。

但是我如何在不执行每一步的情况下模拟 Web 服务呢?我应该让模拟对象只返回一个 XML 文件吗?

这不是关于代码,而是关于方法

我正在使用 JUnit 4.x 和 Mockito 1.7

【问题讨论】:

    标签: web-services unit-testing junit mocking mockito


    【解决方案1】:

    我认为这里真正的问题是您有一个调用和创建 Web 服务的单例,因此很难插入一个模拟的。

    您可能必须添加(可能是包级别)对单例类的访问权限。例如,如果构造函数看起来像

    private GeoLocationFactory(WebService service) {
       ...
    }
    

    您可以使构造函数包级别,只需使用模拟的 Web 服务创建一个。

    您也可以通过添加一个 setter 方法来设置 web 服务,尽管我不喜欢可变单例。同样在这种情况下,您必须记住之后取消设置网络服务。

    如果 Web 服务是在某个方法中创建的,您可能必须使 GeoLocationFactory 可扩展以替代模拟服务。

    您也可以考虑删除单例本身。网上有文章,可能这里有关于如何做到这一点的文章。

    【讨论】:

      【解决方案2】:

      您确实希望将从 web 服务返回的结果模拟为将使用该结果的代码。在上面的示例代码中,您似乎在模拟 mDocument,但您确实想传入从 web 服务的模拟实例返回的 mDocument 实例,并断言从 geoLocationFetcher 返回的 locationBean 与 A_LOCATION_BEAN 的值匹配。

      【讨论】:

      • 谢谢,我明白了。那么你将如何“模拟网络服务”呢?
      • 通常我会声明一个接口并创建一个实现接口并实例化 Web 服务的 Web 服务包装器
      • 所以你只检查结果,你的 web 服务消费者返回?
      【解决方案3】:

      最简单的选择是模拟 WebService 客户端,

      when(geoLocationFetcher.extractGeoLocationFromXml(anyString()))
          .thenReturn("<location/>");
      

      您可以修改代码以从文件系统中读取响应 xml。

      可在此处找到示例代码:Mocking .NET WebServices with Mockito

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-24
        • 2012-10-27
        • 1970-01-01
        相关资源
        最近更新 更多