Testing Flask Applications(Flaskアプリケーションのテスト)
6495 ワード
公式文書の7章を起点とする.
次にselfを見てみましょうapp = flaskr.app.test_Client()このコードはいったい何をしているのか.
デフォルトtest_client_classはNone.だからFlaskClient.FlaskClientはWerkzeugから継承されています.テストのClientですが、いくつかの方法が追加されています.with flaskr.app.app_context(): flaskr.init_db()のapp_context()メソッドは、AppContextにapp,url_が含まれていることを分析しました.adapter,g.作成したAppContextにg変数が含まれている以上flaskr.init_db()はスムーズに実行できます.
7.8節のKeeping the Context Aroundには、小さなセグメントコードがあります.
flaskが「Working outside of request context.」ではなくrequestを正常に動作させる方法を見てみましょう.のエラーapp.test_request_context():...で、明らかなRequestContextがpushされています.でもapp.test_Client()は少し曲がって、そんなに明らかではありません.
enter関数でself.preserve_ContextはTrueに設定.FlaskClientのインスタンスを返します.FlaskClientはWerkzeugのClientから継承する.
c.get('/?tequila=42')を使用してgetメソッドを呼び出すと、実際にはreturn selfである.open(*args, **kw).
FlaskClientはClientのopenメソッドを書き換えた.kwargsのflask._をpreserve_contextパラメータはselfに設定.preserve_つまりTrueです続いてkwargsがmake_に転送されますtest_environ_builder関数
次にmakeを見てみましょうtest_environ_ビルダーのパラメータには、次のものがあります. app=Flaskの例である. path = '/?tequila=42' base_url = None args = () kwargs = {'method': 'GET', 'environ_overrides': {'flask._preserve_context': True}}
make_test_environ_ビルダーはEnvironBuilderに戻るEnvironBuilderに入力されたパラメータはbase_を除きます.urlが'に変わりますhttp://localhost他は変わっていない.EnvironBuilderを返します.例.次にClientを呼び出します.open(...),ClienでOpen()関数では、builderのkwargsの'flask._を主に見ます.preserve_context'はwsgiにどのように伝わりますか?appの中の.
self.run_wsgi_appでは、’flask.preserve_context'はenvironに含まれています.
今振り返ると、私たちはまたよく知っているFlaskに入りました.wsgi_app(...)の処理フローにおいて.
wsgi_appは最後に自動的にpop ctxする.次に、関連コードを詳しく分析します.
そこで真相が明らかになりました.原理auto_popの最初の行のコードはrequestを判断することである.Environに'flask._があるかどうかpreserve_context′変数は、他の2つの判断条件がデバッグに関連する可能性があり、一時的に無視する.それでpreserved = True. もちろんselfは実行する.pop(exc)です.実行しない結果、RequestContextはまだ存在します.request_ctx_stackの上には、もちろんrequestを正常に取得することができます.args['tequila']の値は、working outside of contextのエラーが発生しません.では、pop ctxはいつですか.答えはここにある.
これで、公式ドキュメント7.8節のコードの背後原理も明らかになった.
# 7.2 The Testing Skeleton.
import os
import flaskr
import unittest
import tempfile
class FlaskTestCase(unittest.TestCase):
def setUp(self):
self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp()
flaskr.app.config['TESTING'] = True
self.app = flaskr.app.test_client()
with flaskr.app.app_context():
flaskr.init_db()
def tearDown(self):
os.close(self.db_fd)
os.unlink(flaskr.app.config['DATABASE'])
if __name__ == '__main__':
unittest.main()
次にselfを見てみましょうapp = flaskr.app.test_Client()このコードはいったい何をしているのか.
# app.py
def test_client(self, use_cookies=True, **kwargs):
cls = self.test_client_class
if cls is None:
from flask.testing import FlaskClient as cls
return cls(self, self.response_class, use_cookies=use_cookies, **kwargs)
デフォルトtest_client_classはNone.だからFlaskClient.FlaskClientはWerkzeugから継承されています.テストのClientですが、いくつかの方法が追加されています.with flaskr.app.app_context(): flaskr.init_db()のapp_context()メソッドは、AppContextにapp,url_が含まれていることを分析しました.adapter,g.作成したAppContextにg変数が含まれている以上flaskr.init_db()はスムーズに実行できます.
7.8節のKeeping the Context Aroundには、小さなセグメントコードがあります.
app = flask.Flask(__name__)
with app.test_client() as c:
rv = c.get('/?tequila=42')
assert request.args['tequila'] == '42'
flaskが「Working outside of request context.」ではなくrequestを正常に動作させる方法を見てみましょう.のエラーapp.test_request_context():...で、明らかなRequestContextがpushされています.でもapp.test_Client()は少し曲がって、そんなに明らかではありません.
# testing.py
def __enter__(self):
if self.preserve_context:
raise RuntimeError('Cannot nest client invocations')
self.preserve_context = True
return self
enter関数でself.preserve_ContextはTrueに設定.FlaskClientのインスタンスを返します.FlaskClientはWerkzeugのClientから継承する.
# test.py in Werkzeug.
def get(self, *args, **kw):
"""Like open but method is enforced to GET."""
kw['method'] = 'GET'
return self.open(*args, **kw)
c.get('/?tequila=42')を使用してgetメソッドを呼び出すと、実際にはreturn selfである.open(*args, **kw).
def open(self, *args, **kwargs):
kwargs.setdefault('environ_overrides', {}) \
['flask._preserve_context'] = self.preserve_context
as_tuple = kwargs.pop('as_tuple', False)
buffered = kwargs.pop('buffered', False)
follow_redirects = kwargs.pop('follow_redirects', False)
builder = make_test_environ_builder(self.application, *args, **kwargs)
return Client.open(self, builder,
as_tuple=as_tuple,
buffered=buffered,
follow_redirects=follow_redirects)
FlaskClientはClientのopenメソッドを書き換えた.kwargsのflask._をpreserve_contextパラメータはselfに設定.preserve_つまりTrueです続いてkwargsがmake_に転送されますtest_environ_builder関数
def make_test_environ_builder(app, path='/', base_url=None, *args, **kwargs):
http_host = app.config.get('SERVER_NAME')
app_root = app.config.get('APPLICATION_ROOT')
if base_url is None:
url = url_parse(path)
base_url = 'http://%s/' % (url.netloc or http_host or 'localhost')
if app_root:
base_url += app_root.lstrip('/')
if url.netloc:
path = url.path
if url.query:
path += '?' + url.query
return EnvironBuilder(path, base_url, *args, **kwargs)
次にmakeを見てみましょうtest_environ_ビルダーのパラメータには、次のものがあります.
make_test_environ_ビルダーはEnvironBuilderに戻るEnvironBuilderに入力されたパラメータはbase_を除きます.urlが'に変わりますhttp://localhost他は変わっていない.EnvironBuilderを返します.例.次にClientを呼び出します.open(...),ClienでOpen()関数では、builderのkwargsの'flask._を主に見ます.preserve_context'はwsgiにどのように伝わりますか?appの中の.
# test.py in Werkzeug.
def open(self, *args, **kwargs):
as_tuple = kwargs.pop('as_tuple', False)
buffered = kwargs.pop('buffered', False)
follow_redirects = kwargs.pop('follow_redirects', False)
environ = None
if not kwargs and len(args) == 1:
if isinstance(args[0], EnvironBuilder):
# builder environ.
environ = args[0].get_environ() #
self.run_wsgi_appでは、’flask.preserve_context'はenvironに含まれています.
def run_wsgi_app(app, environ, buffered=False):
environ = _get_environ(environ)
response = []
buffer = []
...
app_rv = app(environ, start_response) #
今振り返ると、私たちはまたよく知っているFlaskに入りました.wsgi_app(...)の処理フローにおいて.
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
ctx.push()
...
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error) #
wsgi_appは最後に自動的にpop ctxする.次に、関連コードを詳しく分析します.
def auto_pop(self, exc):
if self.request.environ.get('flask._preserve_context') or \
(exc is not None and self.app.preserve_context_on_exception):
self.preserved = True
self._preserved_exc = exc
else:
self.pop(exc)
そこで真相が明らかになりました.原理auto_popの最初の行のコードはrequestを判断することである.Environに'flask._があるかどうかpreserve_context′変数は、他の2つの判断条件がデバッグに関連する可能性があり、一時的に無視する.それでpreserved = True. もちろんselfは実行する.pop(exc)です.実行しない結果、RequestContextはまだ存在します.request_ctx_stackの上には、もちろんrequestを正常に取得することができます.args['tequila']の値は、working outside of contextのエラーが発生しません.では、pop ctxはいつですか.答えはここにある.
# testing.py
def __exit__(self, exc_type, exc_value, tb):
# preserve-context False.
self.preserve_context = False
# ctx, , top.pop().
top = _request_ctx_stack.top
if top is not None and top.preserved:
top.pop()
これで、公式ドキュメント7.8節のコードの背後原理も明らかになった.