私はチュートリアルに従ってflask Web開発を学びます。これが、その単体テストファイルです。
_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アプリケーションと統合するプロセスには、正確に2つの要件があります。
……。
通常、Webフレームワークのイベントシステムと統合して「onrequest end」イベントを確立することにより、Webリクエストの終了時に
scoped_session.remove()
が呼び出されるようにします。
私の質問は、なぜdb.session.remove()
を呼び出す必要があるのですか?
db.session.commit()
が呼び出されない限り、データベースは変更されないと思います。また、この行をコメントアウトしても、アプリケーションは単体テストに合格できます。
Flask-SQLAlchemyとSQLAlchemyの両方のドキュメントを調べましたが、前者はdb.session.remove()
についても言及していませんが、後者は抽象的すぎて理解できません。
上記のフローを使用すると、
Session
をWebアプリケーションと統合するプロセスには、正確に2つの要件があります。
- ……。
- 通常、Webフレームワークのイベントシステムと統合して「onrequest end」イベントを確立することにより、Webリクエストの終了時に
scoped_session.remove()
が呼び出されるようにします。
SQLAlchemyでは、Webアプリケーションのセッションをスコープにする必要があるため、上記のアクションについて説明します。 )、つまり、各リクエストハンドラは独自のセッションを作成および破棄します。
これが必要なのは、Webサーバーをマルチスレッド化できるため、複数の要求が同時に処理され、それぞれが異なるデータベースセッションで動作する可能性があるためです。
このシナリオはFlask-SQLAlchemyによって美しく処理され、リクエストごとに新しいスコープセッションまたは新しいスコープセッションを作成します。さらに掘り下げると、 ここ であることがわかります。また、app.teardown_appcontext
(Flask> = 0.9)、app.teardown_request
(Flask 0.7-0.8)、app.after_request
(Flask <0.7)の場合、ここでdb.session.remove()
と呼ばれます。
testing環境は、アプリケーションコンテキストをプッシュ/ポップしないため、実際のリクエストの環境を完全には複製しません。そのため、リクエストの終了時にセッションが削除されることはありません。
補足として、client.get()
を呼び出すときに、before_request
およびafter_request
に登録されている関数も呼び出されないことに注意してください。
setUp()
を手動でプッシュしてtearDown()
をポップする代わりに、テストに小さな変更を加えるだけで、アプリケーションコンテキストを自動的にプッシュしてポップすることができます。
def test_foo(self):
with app.app_context():
client = app.test_client()
# do testing here for your endpoints
この変更により、db.session.remove()
を手動で書き込まなくてもテストに合格します。
Flask-Testingのドキュメントが間違っているか、古くなっている可能性が高いようです。ある時点で説明どおりに機能したかもしれませんが、現在のFlaskおよびFlask-SQLAlchemyバージョンでは正確ではありません。
これがお役に立てば幸いです。
プロジェクト全体を調べるまで、なぜdb.session.remove()
が必要なのか理解できません。
これは、config.py
でSQLALCHEMY_COMMIT_ON_TEARDOWN
がTrue
に設定されているためです。その結果、db.session
が破棄されない場合、db.session
に加えられた変更は自動コミットされます。