2017-09-05 70 views
0

我想为Tornado网络应用程序编写单元测试,我在如何正确测试使用选项模块的代码时遇到了问题。我定义了几个选项并在应用程序的多个地方访问它们,因此,我想在单元测试中测试不同的选项组合。龙卷风单元测试与tornado.options

包含一切

一个非常简单的例子是:

import tornado.web 
from tornado.options import define, options 
import tornado.ioloop 


def define_options(): 
    define('myoption', type=str, default='MyValue') 


class ExampleHandler(tornado.web.RequestHandler): 
    def get(self): 
     self.write({ 
      'myoption': options.myoption 
     }) 


def make_app(): 
    ROUTES = [ 
     (r'/', ExampleHandler) 
    ] 
    return tornado.web.Application(ROUTES) 


def run(): 
    define_options() 
    app = make_app() 
    app.listen(8080) 
    tornado.ioloop.IOLoop.current().start() 


if __name__ == '__main__': 
    run() 

最大的问题似乎是,该选项持续了那个正在运行所有测试,我没有看到,我应该叫define_options以及如何更改单个测试参数而不会影响所有其他测试。取的测试代码下面的例子:

import tornado.testing 
from demo import define_options, make_app 

class Test1(tornado.testing.AsyncHTTPTestCase): 
    def setUp(self): 
     define_options() 
     super().setUp() 

    def get_app(self): 
     return make_app() 

    def test1(self): 
     response = self.fetch('/') 
     print(response) 

这工作得很好,但只要我添加第二个测试方法:

def test2(self): 
    response = self.fetch('/') 
    print(response) 

我会得到这样的错误:

File "/Users/jan/Documents/demo/demo/demo.py", line 7, in define_options 
    define('myoption', type=str, default='MyValue') 
    File "/Users/jan/anaconda/envs/py3k/lib/python3.4/site-packages/tornado/options.py", line 558, in define 
    callback=callback) 
    File "/Users/jan/anaconda/envs/py3k/lib/python3.4/site-packages/tornado/options.py", line 228, in define 
    (name, self._options[name].file_name)) 
tornado.options.Error: Option 'myoption' already defined in /Users/jan/Documents/demo/demo/demo.py 

我可以将define_options移动到setUpClass,但是当我添加第二个测试类时,我会看到同样的问题。因此,我想知道是否有人遇到这个问题,以及我可以用什么解决方案来运行这些测试。不仅要将define_options放在哪里,因此它只运行一次,而且还可以为不同的测试定义一组不同的选项(从define_options中给出的默认值开始),而不会相互影响测试。

回答

0

tornado.options可以以两种方式使用:

  • 使用全局单。在此模式下,您可以在导入时间处拨打tornado.options.define,通过tornado.options.options访问结果,并使用tornado.options模块中的顶级函数解析命令行(或配置文件)。在这个例子中,你会删除你的define_options()函数,并在顶层定义所有的选项。
  • 使用不同的tornado.options.OptionParser对象。在此模式下,您需要在define_options()函数中创建一个OptionParser()对象,请调用define()并解析方法,而不是options模块, and return it so that other code accesses the values through this object instead of tornado.options.options中的函数。

注意的是,全球单身的风格是,tornado.options模块最初设计的目的是使用(它吸引了来自谷歌的C++ gflags包的灵感)的方式。在这种风格中有一点可能有点棘手,那就是临时更改标志的值来进行测试。 unittest.mock包在tornado.options中使用的魔法对象有点麻烦,所以您必须使用帮助器方法mockable()