我正在编写一个带有全局对象的应用程序,只要应用程序处于活动状态,它就应该存在。不同的端点应该改变全局对象。
下面是我的服务器,其中有一个示例模型对象,可以在虚拟端点调用上进行变异。
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)
对于应用程序上下文,我必须对我的全局对象做错误的操作。我对testing documents进行了仔细研究,但似乎找不到我需要的东西。
当应用程序上下文超出范围时(如在我的测试中),如何确保我的foo
对象被销毁?为什么我的单元测试套件不会改变在foo
上创建的setUp
对象?
我认为可以修改app
中的全局server.py
对象,但是当我打印foo
时,我发现它并未在我的测试范围内定义套件。
答案 0 :(得分:0)
因为del foo
只取消绑定变量foo
。如果您有foo = g._foo
,则调用del foo
不会取消绑定g._foo
,而只取消绑定foo
。
del
不用于删除对象。它从范围中释放变量名称。
答案 1 :(得分: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
对象。
所有测试都通过。