代码之家  ›  专栏  ›  技术社区  ›  guerda

模拟Web服务的策略

  •  1
  • guerda  · 技术社区  · 16 年前

    我正在实现一个使用WebService的客户机。我想减少依赖性并决定模拟WebService。
    我用 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 . 在我看来,它太细了。

    但是我怎么能在不提供EveryStep的情况下模拟Web服务呢?我应该让模拟对象只返回一个XML文件吗?

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

    我用的是Junit4.x和Mockito 1.7

    3 回复  |  直到 13 年前
        1
  •  1
  •   lomaxx    16 年前

    您真的想要模拟从WebService返回到将要使用结果的代码的结果。在上面的示例代码中,您似乎在模拟MDocument,但您确实希望传递一个从Web服务的模拟实例返回的MDocument实例,并断言从geoLocationFetcher返回的locationBean与“location”be an的值匹配。

        2
  •  2
  •   Kathy Van Stone    16 年前

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

    您可能需要添加(可能是包级别)对singleton类的访问。例如,如果构造函数看起来像

    private GeoLocationFactory(WebService service) {
       ...
    }
    

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

    或者,您可以通过添加setter方法来设置WebService,尽管我不喜欢可变的singleton。同样,在这种情况下,您必须记住稍后取消设置WebService。

    如果WebService是在方法中创建的,则可能需要使geolocationFactory可扩展以替换模拟服务。

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

        3
  •  1
  •   Sunil Manheri    13 年前

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

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

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

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