测试urllib2应用程序,HTTP响应从文件加载

1 投票
2 回答
999 浏览
提问于 2025-04-16 01:29

我的Python应用程序使用urllib2向很多网址发送HTTP请求。我想建立一个单元测试套件,来测试我的数据解析和错误处理代码。

我有一个目录,里面存放着测试数据,包含多个文件,每个文件里都有一个HTTP响应,包括头信息和响应数据。(我用curl -i命令获取的)在某些情况下,这些文件里还包含HTTP错误信息(这是测试错误处理所需要的)。

理想情况下,我想创建一个模拟对象,替代urllib2.urlopen,并返回一个模拟的响应对象。

我在想有没有简单的方法让urllib2直接从文件加载HTTP响应,并解析这些数据,创建出合适的响应对象(就像是从网址读取的响应一样)。

我试过用“file://”协议构造的URL,但文件顶部的HTTP响应头没有被正确读取或解析。

另外,我在考虑写一个小的网络服务器类来提供这些测试文件,但这似乎比我想要的工作量要大一些。如果能让urllib2从我已经保存的文件中的HTTP响应重建响应对象,那就简单多了(而不需要再搭建一个网络服务器来提供这些文件)。

有没有什么好主意?

2 个回答

1

用服务器的方法其实并不会增加工作量,反而可能是你所有选择中最简单、最省事的。

可以看看这个链接: http://docs.python.org/library/simplehttpserver.html

这是一段只有7行的Python程序,当你在某个文件夹下运行它时,它会通过HTTP把这个文件夹里的所有文件(包括子文件夹里的文件)都提供出来。

你可以让你的单元测试代码来启动和停止这个服务器,这样即使不在测试的时候也不用一直让它运行。

2

我觉得最好的办法是模拟一个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之后的第一个参数),并且应该忽略后面的关键字参数(这些参数用于设置超时时间)。

mockconget_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)。

撰写回答