我正在学习烧瓶网络开发的教程,这是它的单元测试文件:
import unittest
from flask import current_app
from app import create_app, db
class BasicsTestCase(unittest.TestCase):
def setUp(self):
self.app = create_app('testing')
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_foo(self):
pass
另外,我在SQLAlchemy document中找到了这些句子:
使用上述流程,整合
Session
的过程 Web应用程序有两个要求:
...
确保在Web请求结束时调用
scoped_session.remove()
,通常是通过与Web框架的事件系统集成到 建立“请求结束”事件。
我的问题是:为什么我需要拨打db.session.remove()
?
我认为只要不调用db.session.commit()
,就不会修改数据库。此外,当我注释掉这一行时,应用程序仍然可以通过单元测试。
我已经查阅了Flask-SQLAlchemy和SQLAlchemy的文档,但前者甚至没有提到db.session.remove()
,而后者太抽象了,我无法理解。
答案 0 :(得分:11)
使用上述流程,将
Session
与Web应用程序集成的过程正好有两个要求:
- ......
- 确保在Web请求结束时调用
scoped_session.remove()
,通常是通过与Web框架的事件系统集成来建立“on request end”事件。
在 SQLAlchemy 中,提到了上述操作,因为Web应用程序中的会话应该作用域,这意味着每个请求处理程序都会创建并销毁自己的会话。
这是必要的,因为Web服务器可以是多线程的,因此可以同时提供多个请求,每个请求使用不同的数据库会话。
这种情况由 Flask-SQLAlchemy 精心处理,它为每个请求创建一个新的或新的范围会话。如果你进一步挖掘,你会发现here,它还会在app.teardown_appcontext
(对于Flask> = 0.9),app.teardown_request
(对于Flask 0.7-0.8),{{{ 1}}(对于Flask< 0.7),这里是调用app.after_request
的地方。
测试环境并未完全复制实际请求的环境,因为它不会推送/弹出应用程序上下文。因此,在请求结束时永远不会删除会话。
作为旁注,请注意,当您致电db.session.remove()
时,注册before_request
和after_request
的功能也不会被调用。
您可以通过对测试进行少量更改来强制推送和弹出应用程序上下文,而不是手动推入client.get()
并弹出setUp()
:
tearDown()
通过此更改,测试通过而无需手动编写def test_foo(self):
with app.app_context():
client = app.test_client()
# do testing here for your endpoints
。
Flask-Testing的文档似乎是错误的或更可能过时。也许事情就像他们在某些时候描述的那样,但对于当前的Flask和Flask-SQLAlchemy版本来说,这并不准确。
我希望这有帮助!
答案 1 :(得分:2)
在我检查整个项目之前,我不明白为什么db.session.remove()
是必要的:
这是因为在config.py
中,SQLALCHEMY_COMMIT_ON_TEARDOWN
设置为True
。因此,如果db.session
未被销毁,则对db.session
所做的更改将自动提交。