模拟Web服务的策略

时间:2009-04-30 05:44:14

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

我正在实现一个使用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。 在我看来,它过于细化了。

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

这不是代码,而是方法

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

3 个答案:

答案 0 :(得分:2)

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

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

private GeoLocationFactory(WebService service) {
   ...
}

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

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

如果在方法中创建了webservice,则可能必须使GeoLocationFactory可扩展以替换模拟服务。

您也可以考虑删除单身人士。有在线文章,可能在这里有关于如何做到这一点。

答案 1 :(得分:1)

你真的想要模仿从webservice返回到将使用结果的代码的结果。在上面的示例代码中,您似乎是在模拟mDocument但是您确实希望传入已从Web服务的模拟实例返回的mDocument实例,并断言从geoLocationFetcher返回的locationBean与A_LOCATION_BEAN的值匹配。

答案 2 :(得分:1)

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

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

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

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