Gab*_*ley 26 python unit-testing urllib urllib2
我有一段代码,我无法弄清楚如何进行单元测试!该模块使用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...
Run Code Online (Sandbox Code Playgroud)
我的第一个想法是挑选响应并加载它以进行测试,但显然urllib的响应对象是不可序列化的(它引发了异常).
仅仅从响应主体保存XML并不理想,因为我的代码也使用了头信息.它旨在作用于响应对象.
当然,在单元测试中依赖外部数据来源是一个可怕的想法.
那么我该如何为此编写单元测试呢?
Joh*_*ooy 26
urllib2的有一个调用的函数build_opener()
和install_opener()
你应该用嘲笑的行为urlopen()
import urllib2
from StringIO import StringIO
def mock_response(req):
if req.get_full_url() == "http://example.com":
resp = urllib2.addinfourl(StringIO("mock file"), "mock message", req.get_full_url())
resp.code = 200
resp.msg = "OK"
return resp
class MyHTTPHandler(urllib2.HTTPHandler):
def http_open(self, req):
print "mock opener"
return mock_response(req)
my_opener = urllib2.build_opener(MyHTTPHandler)
urllib2.install_opener(my_opener)
response=urllib2.urlopen("http://example.com")
print response.read()
print response.code
print response.msg
Run Code Online (Sandbox Code Playgroud)
最好是你可以编写一个mock urlopen(可能还有Request),它提供了所需的最小接口,就像urllib2的版本一样.然后你需要让你的函数/方法使用它能够以某种方式接受这个模拟urlopen,urllib2.urlopen
否则使用它.
这是相当多的工作,但值得.请记住,python对ducktyping非常友好,所以你只需要提供一些响应对象的属性来模拟它.
例如:
class MockResponse(object):
def __init__(self, resp_data, code=200, msg='OK'):
self.resp_data = resp_data
self.code = code
self.msg = msg
self.headers = {'content-type': 'text/xml; charset=utf-8'}
def read(self):
return self.resp_data
def getcode(self):
return self.code
# Define other members and properties you want
def mock_urlopen(request):
return MockResponse(r'<xml document>')
Run Code Online (Sandbox Code Playgroud)
当然,其中一些很难被模拟,因为例如我认为正常的"标题"是一个HTTPMessage,它实现了像case-insensitive标题名称这样的有趣的东西.但是,您可以使用响应数据简单地构造HTTPMessage.
构建一个单独的类或模块,负责与外部源进行通信.
使这个类能够成为测试的两倍.你正在使用python,所以你在那里很漂亮; 如果您使用的是C#,我建议使用接口或虚拟方法.
在单元测试中,插入外部Feed类的测试双.测试您的代码是否正确使用该类,假设该类正确地执行与外部资源通信的工作.让你的测试双重返回假数据而不是实时数据; 测试数据的各种组合,当然还有urllib2可能抛出的异常.
Aand ......就是这样.
您无法有效地自动化依赖外部源的单元测试,因此您最好不要这样做.在您的通信模块上运行偶尔的集成测试,但不要将这些测试作为自动测试的一部分.
编辑:
请注意我的回答和@Crast的回答之间的区别.两者基本上都是正确的,但它们涉及不同的方法.在Crast的方法中,您在库本身上使用了测试双精度.在我的方法中,您将库的使用抽象为一个单独的模块并测试该模块的两倍.
你使用哪种方法完全是主观的; 那里没有"正确"的答案.我更喜欢我的方法,因为它允许我构建更多模块化,灵活的代码,这是我重视的.但是在编写额外代码方面需要付出代价,这在某些敏捷情况下可能无法得到重视.
归档时间: |
|
查看次数: |
7700 次 |
最近记录: |