潇湘夜雨

分类

  • 源代码阅读 (20)
  • 设计模式 (3)
  • 科研 (6)
  • 思想 (2)
  • 技术 (18)
  • 工具 (4)
  • 虚拟机 (1)
  • java (11)
  • c语言 (4)
  • 读书 (1)
  • 操作系统 (1)
  • 英语 (10)
  • 计算机系统 (3)
  • 生活 (1)

归档

  • 2014-08 (1)
  • 2014-07 (5)
  • 2014-05 (12)
  • 2014-04 (3)
  • 2014-03 (11)
  • 2014-02 (6)
  • 2014-01 (3)
  • 2013-11 (10)
  • 2013-10 (3)
  • 2010-09 (1)
  • web.py 源代码分析之 web.test.application.test_reloader
    1. 2013-11-14
    2. 源代码阅读

    分模块测试

    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函数,得到了返回的字符串。

    从整个过程可以看出,没有启动服务器的代码,只是不断地调用 函数,最终来到 GET 函数。

    Read More ...
  • web.py 源代码分析之 web.test.application.test_UppercaseMethods
    1. 2013-11-14
    2. 源代码阅读

    分模块测试

    application.py

    对 application.py 的测试,调用命令:

    python test/application.py
    
    Read More ...
  • web.py 源代码分析之 web.test.application.testRedirect
    1. 2013-11-14
    2. 源代码阅读

    分模块测试

    application.py

    对 application.py 的测试,调用命令:

    python test/application.py
    
    Read More ...
  • web.py 源代码分析之 web.test.application
    1. 2013-11-14
    2. 源代码阅读

    分模块测试

    application.py

    对 application.py 的测试,调用命令:

    python test/application.py
    
    Read More ...
  • web.py 源代码分析之 web.test 主要文件及测试流程
    1. 2013-11-14
    2. 源代码阅读

    目录文件说明

    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自动单元测试框架,即unittest模块。关于 unittest ,可以参考这篇文章: Python自动单元测试框架

    Read More ...
« Prev 1 2 3 4 5 6 7 8 9 10 11 Next »
Copyright (c) minixalpha 2014