我有一段代码,我不知道如何进行单元测试!该模块使用urllib2从外部XML提要(twitter、flickr、youtube等)中提取内容。这里有一些伪代码:
params = (url, urlencode(data),) if data else (url,)
req = Request(*params)
response = urlopen(req)
#check headers, content-length, etc...
#parse the response XML with lxml...
我的第一个想法是pickle响应并加载它进行测试,但显然urllib的响应对象是不可更改的(它引发了一个异常)。
仅仅从响应体保存XML并不理想,因为我的代码也使用头信息。它被设计成作用于响应对象。
当然,在单元测试中依赖外部数据源是一个可怕的想法。
那么我该如何编写一个单元测试呢?
urllib2有一个名为
build_opener()
和install_opener()
的函数,您应该使用它来模拟urlopen()
的行为最好是编写一个模拟urlopen(可能还有请求),它提供了与urllib2的版本类似的最低要求的接口。然后,您需要让使用它的函数/方法以某种方式接受这个模拟urlopen,并使用
urllib2.urlopen
否则。这是相当多的工作,但值得。请记住,python对ducktyping非常友好,所以您只需要提供响应对象属性的一些外观来模拟它。
例如:
当然,其中一些很难模拟,因为例如,我相信普通的“headers”是一个HTTPMessage,它实现了一些有趣的东西,比如不区分大小写的头名称。但是,您可以使用响应数据简单地构造HTTPMessage。
构建一个单独的类或模块,负责与外部feed通信。
使这个类能够成为test double。你使用的是python,所以你在这方面非常出色;如果你使用的是C#,我建议要么使用接口方法,要么使用虚拟方法。
在单元测试中,插入外部feed类的test double。测试代码是否正确地使用了类,假设该类正确地完成了与外部资源通信的工作。让您的测试double返回假数据而不是实时数据;测试数据的各种组合,当然还有urllib2可能抛出的异常。
还有。。。就这样。
您不能有效地自动化依赖于外部源的单元测试,所以最好不要这样做。在通信模块上偶尔运行集成测试,但不要将这些测试作为自动化测试的一部分。
编辑:
我的答案和克拉斯特的答案有什么不同。两者基本上都是正确的,但它们涉及不同的方法。在Crast的方法中,在库本身使用test double。在我的方法中,将库的使用抽象为一个单独的模块,并对该模块进行双重测试。
你用哪种方法完全是主观的,没有“正确”的答案。我更喜欢我的方法,因为它允许我构建更模块化、更灵活的代码,这是我所看重的。但是,在编写额外的代码方面,这是需要付出代价的,而在许多敏捷环境中,这一点可能没有价值。
相关问题 更多 >
编程相关推荐