测试urllib2应用程序,HTTP响应从文件加载
我的Python应用程序使用urllib2向很多网址发送HTTP请求。我想建立一个单元测试套件,来测试我的数据解析和错误处理代码。
我有一个目录,里面存放着测试数据,包含多个文件,每个文件里都有一个HTTP响应,包括头信息和响应数据。(我用curl -i命令获取的)在某些情况下,这些文件里还包含HTTP错误信息(这是测试错误处理所需要的)。
理想情况下,我想创建一个模拟对象,替代urllib2.urlopen,并返回一个模拟的响应对象。
我在想有没有简单的方法让urllib2直接从文件加载HTTP响应,并解析这些数据,创建出合适的响应对象(就像是从网址读取的响应一样)。
我试过用“file://”协议构造的URL,但文件顶部的HTTP响应头没有被正确读取或解析。
另外,我在考虑写一个小的网络服务器类来提供这些测试文件,但这似乎比我想要的工作量要大一些。如果能让urllib2从我已经保存的文件中的HTTP响应重建响应对象,那就简单多了(而不需要再搭建一个网络服务器来提供这些文件)。
有没有什么好主意?
2 个回答
用服务器的方法其实并不会增加工作量,反而可能是你所有选择中最简单、最省事的。
可以看看这个链接: http://docs.python.org/library/simplehttpserver.html
这是一段只有7行的Python程序,当你在某个文件夹下运行它时,它会通过HTTP把这个文件夹里的所有文件(包括子文件夹里的文件)都提供出来。
你可以让你的单元测试代码来启动和停止这个服务器,这样即使不在测试的时候也不用一直让它运行。
我觉得最好的办法是模拟一个httplib.HTTPConnection
的子集(为了方便,下面我们叫这个类mockcon
),然后使用它来添加一个处理器,并且继承HTTPHandler
(这样在build_opener
中使用时,就可以替代默认的HTTPHandler
)。
class MockHTTPHandler(urllib2.HTTPHandler):
def http_open(self, req):
return self.do_open(mockcon, req)
这个mockcon
类必须提供一个do_open
方法的调用——其中一些可以是虚假的(也就是说,接受并忽略任意的参数和关键字参数,什么都不做):
set_debuglevel
_set_tunnel
request
(可能对request
的第二个参数感兴趣,因为它提供了URL的“选择器”部分)。
mockcon
的__init__
方法需要把URL的主机部分作为第一个参数(也就是在self
之后的第一个参数),并且应该忽略后面的关键字参数(这些参数用于设置超时时间)。
mockcon
的get_response
方法(除了self
之外没有其他参数)必须返回一个HTTP响应对象——也就是说,它应该是一个像文件一样可读的对象,并且还应该有属性.msg
、.status
和.reason
,以及一个方法get_full_url()
来返回URL。
你可以使用一个实际的httplib.HTTPResponse
实例来实现这个功能,但你必须用一个虚假的参数来初始化它,这个参数有一个makefile
参数(忽略它的参数和关键字参数,返回任意内容),并且在初始化后,重置它的.fp
参数为一个以rb
模式打开的文件,确保这个文件返回的字节和真实的HTTP响应在其套接字上接收到的字节完全一致。
我认为,为整个urllib2.urlopen
调用构建一个完整的模拟可能比尝试重用大部分urllib2
(以及它内部使用的httplib
)的功能要简单,尽管这可能没有你认为的“本地web服务器”方法那么简单,后者似乎需要更多的工作。不过,考虑这三种方法都是值得的(模拟的方式肯定是最轻量级和最快的,而本地web服务器则是最慢的……当然,还需要通过在URL前加上http://localhost:someport/
来修改这些URL)。