-
- 2013-11-14
- 源代码阅读
分模块测试
application.py
对 application.py 的测试,调用命令:
python test/application.py
test_reloader(self)
def test_reloader(self): write('foo.py', data % dict(classname='a', output='a')) import foo app = foo.app self.assertEquals(app.request('/').data, 'a') # test class change time.sleep(1) write('foo.py', data % dict(classname='a', output='b')) self.assertEquals(app.request('/').data, 'b') # test urls change time.sleep(1) write('foo.py', data % dict(classname='c', output='c')) self.assertEquals(app.request('/').data, 'c')
总的来说,这个过程会生成一个 foo.py 文件
import web urls = ("/", "a") app = web.application(urls, globals(), autoreload=True) class a: def GET(self): return "a"
这是一个典型的 web 服务端应用程序,表示对
/
发起GET
请求时,会调用class a
中的GET
函数,测试就是看看 web.application 是否可以正常完成任务,即是否可以正确返回"a"下面详细看代码。
首先使用
write
生成了一个foo.py
程序:write('foo.py', data % dict(classname='a', output='a'))
write 源代码:
def write(filename, data): f = open(filename, 'w') f.write(data) f.close()
data 定义: ```python data = """ import web
urls = ("/", "%(classname)s") app = web.application(urls, globals(), autoreload=True)
class %(classname)s: def GET(self): return "%(output)s"
""" ```
data
相当于一个小型 web 程序的模板,类名和返回值由 一个dict
指定,生成一个字符串,由write
生成文件。下面是类别和返回值为
a
时的foo.py
import web urls = ("/", "a") app = web.application(urls, globals(), autoreload=True) class a: def GET(self): return "a"
测试的方式采用
TestCase
中的assertEquals
函数,比较 实际值与预测值。import foo app = foo.app self.assertEquals(app.request('/').data, 'a')
app.request('/')
会得到一个Storage类型的值:<Storage {'status': '200 OK', 'headers': {}, 'header_items': [], 'data': 'a'}>
其中的
data
就是foo.py
中GET
返回的值。我对这个
app.request('/')
是比较困惑的。以foo.py
为例, 之前写程序时,一般是有一个这样的程序:import web urls = ("/", "a") app = web.application(urls, globals(), autoreload=True) class a: def GET(self): return "a" if __name__ == "__main__": app.run()
然后在浏览器中请求
0.0.0.0:8080/
。 而在request
之前,也没看到run
啊,怎么就能request
回 数据呢,而且通过上述代码运行后,程序会一直运行直到手动关闭, 而request
的方式则是测试完后,整个程序也结束了。所以,下一部,想比较一下
application.run
和application.request
的不同。我们只看关键部分,即返回的值是如何被设值的。
在
web.application.request
中:def request(self, localpart='/', method='GET', data=None, host="0.0.0.0:8080", headers=None, https=False, **kw): ... response = web.storage() def start_response(status, headers): response.status = status response.headers = dict(headers) response.header_items = headers response.data = "".join(self.wsgifunc()(env, start_response)) return response
上述代码中
self.wsgifunc()(env, start_response)
比较另人困惑, 我还以为是调用函数的新方式呢,然后看了一下wsgifunc
的代码, 它会返回一个函数wsgi
,wsgi
以(env, start_response)
为参数。 在wsgi
内部,又会调用handle_with_processors
,handle_with_processors
会再调用handle
def handle(self): fn, args = self._match(self.mapping, web.ctx.path) return self._delegate(fn, self.fvars, args)
测试了一下,
self._match()
会得到类名,self._delegate
会 得到返回的字符串,即GET
的返回值。进入
self._delegate
, 会最终调用一个关键函数handle_class
:def handle_class(cls): meth = web.ctx.method if meth == 'HEAD' and not hasattr(cls, meth): meth = 'GET' if not hasattr(cls, meth): raise web.nomethod(cls) tocall = getattr(cls(), meth) return tocall(\*args)
参数
cls
值为foo.a
,meth
会得到方法名GET
, 然后tocall
会得到函数a.GET
, 至此,我们终于得以调用,GET
函数,得到了返回的字符串。从整个过程可以看出,没有启动服务器的代码,只是不断地调用 函数,最终来到
Read More ...GET
函数。 -
- 2013-11-14
- 源代码阅读
-
- 2013-11-14
- 源代码阅读
-
- 2013-11-14
- 源代码阅读
-
- 2013-11-14
- 源代码阅读
目录文件说明
README
如何运行测试文件,包含全部测试及分模块测试
调用
$ python test/alltests.py
运行全部测试
调用
$ python test/db.py
运行db模块测试
alltest.py
运行全部测试入口,调用
webtest
模块完成测试# alltest.py if __name__ == "__main__": webtest.main()
webtest.py
我们发现 webtest.py 中并没有 main 函数,而是从
web.test
中导入,# webtest.py from web.test import *
也就是说,如果
web.test
中有main函数的话,webtest.main()
其实是调用web.test
中的main函数。感觉~ 好神奇
web.test
看web目录下的test.py文件,果然发现了main函数,终于找到入口啦~
def main(suite=None): if not suite: main_module = __import__('__main__') # allow command line switches args = [a for a in sys.argv[1:] if not a.startswith('-')] suite = module_suite(main_module, args or None) result = runTests(suite) sys.exit(not result.wasSuccessful())
把这个main函数改掉,再运行一下:
$ python test/alltests.py
果然是运行修改后的函数,所以这里确定是入口。
在进入下一步之前,我们需要学习一下Python自动单元测试框架,即
Read More ...unittest
模块。关于unittest
,可以参考这篇文章: Python自动单元测试框架