0

我正在编写一个具有全局对象的应用程序,该对象应该与应用程序一样长。不同的端点应该改变全局对象。

下面是我的服务器,其中包含一个示例模型对象,该对象要在虚拟端点调用上进行变异。

server.py

#!/usr/bin/env python3

from flask import Flask, g, request

class Foo(object):
    def __init__(self):
        self.bar = None

    def add_bar(self, bar):
        if self.bar is not None:
            raise Exception("You blew it!")
        self.bar = bar

def create_app():
    app = Flask(__name__)
    return app

app = create_app()

def get_foo():
    foo = getattr(g, '_foo', None)
    if foo is None:
        print("foo is None. Creating a foo")
        foo = g._foo = Foo()
    return foo

@app.teardown_appcontext
def teardown_foo(exception):
    foo = getattr(g, '_foo', None)
    if foo is not None:
        print("Deleting foo")
        del foo

@app.route("/add_bar", methods=['POST'])
def bar():
    bar = request.form.get("bar")
    foo.add_bar(bar)
    return "Success"    

if __name__ == "__main__":
    app = create_app()
    app.run('localhost', port=8080)

就像一个优秀的软件开发人员一样,我想对此进行测试。这是我的测试套件:

test.py

#!/usr/bin/env python3

from server import *
import unittest

class FlaskTestCase(unittest.TestCase):
    def setUp(self):
        app.config['TESTING'] = True
        print("Creating an app...")
        self.app = create_app()
        print("Created an app...")
        with self.app.app_context():
            self.foo = get_foo()

    def tearDown(self):
        del self.foo

    def test_add_bar(self):
        with self.app.test_client() as client:
            client.post("/add_bar", data={'bar': "12345"})
            assert self.foo.bar == "12345"

if __name__ == "__main__":
    unittest.main()

当我运行测试时,我注意到我的foo对象从未被删除(通过打印)。这是我运行测试套件时的输出:

13:35 $ ./test.py
Creating an app...
Created an app...
foo is None. Creating a foo
F
======================================================================
FAIL: test_add_bar (__main__.FlaskTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./test.py", line 21, in test_add_bar
    assert self.foo.bar == "12345"
AssertionError

----------------------------------------------------------------------
Ran 1 test in 0.009s

FAILED (failures=1)

关于应用程序上下文,我必须对我的全局对象做一些不正确的事情。我仔细研究了测试文档,但似乎找不到我需要的确切内容。

foo当应用程序上下文超出范围(例如在我的测试中)时,如何确保我的对象被销毁?为什么我的单元测试套件不改变其foo创建的对象setUp

我认为它可能是在修改全局app对象server.py,但是当我打印时foo,我发现它没有在我的测试套件范围内定义。

4

2 回答 2

0

因为del foo只有解绑变量foo。如果你有foo = g._foo,那么调用del foo不会 unbind g._foo,而只会调用foo它自己。

del不用于删除对象。它从作用域中释放一个变量名。

于 2016-08-12T06:56:06.940 回答
0

这是一个奇怪的问题。

app问题是 中的全局对象server.py和在原始 中创建的应用程序之间的干扰test.py。具体来说,由于应用程序正在被导入,它的生命周期就是测试套件的生命周期。

我通过使用删除了全局app对象flask.Blueprint。这是决赛server.py

#!/usr/bin/env python3

from flask import Flask, g, request, Blueprint

main = Blueprint('main', __name__)

def get_foo():
    foo = getattr(g, 'foo', None)
    if foo is None:
        foo = g.foo = Foo()
    return foo

@main.before_request
def before_request():
    foo = get_foo()

@main.route("/add_bar", methods=['POST'])
def bar():
    bar = request.form.get("bar")
    g.foo.add_bar(bar)
    return "Success"

class Foo(object):
    def __init__(self):
        self.bar = None

    def add_bar(self, bar):
        if self.bar is not None:
            raise Exception("You blew it!")
        self.bar = bar

def create_app():
    app = Flask(__name__)
    app.register_blueprint(main)
    @app.teardown_appcontext
    def teardown_foo(exception):
        if g.foo is not None:
            del g.foo
    return app

if __name__ == "__main__":
    app = create_app()
    with app.app_context():
        foo = get_foo()
        app.run('localhost', port=8080)

这是决赛test.py

#!/usr/bin/env python3

from server import create_app, get_foo
import unittest

class FlaskTestCase(unittest.TestCase):
    def setUp(self):
        self.app = create_app()
        self.app_context = self.app.app_context()
        self.app_context.push()
        self.client = self.app.test_client()
        self.foo = get_foo()

    def tearDown(self):
        self.app_context.pop()
        del self.foo

    def test_add_bar_success(self):
        assert self.foo.bar is None
        self.client.post("/add_bar", data={'bar': "12345"})
        assert self.foo.bar == "12345"

    def test_foo_reset_on_new_test(self):
        assert self.foo.bar is None

if __name__ == "__main__":
    unittest.main()

test_foo_reset_on_new_test说明foo与测试套件关联的对象在每次测试时都会重置。

所有测试通过。

于 2016-08-12T18:42:49.480 回答