テストとrequest context¶
Higuma 0.7.0以降のhelperを含みます。通常のview・middleware・CSRF・sessionはtest clientで、
contextに依存する小さな関数はtest_request_contextで、通信仕様は実serverで検証します。
Test clientでdispatchする¶
from higuma import Higuma, request
app = Higuma(__name__, static_folder=None)
@app.post("/echo")
def echo():
return {"value": request.get_json(), "secure": request.scheme == "https"}
client = app.test_client()
response = client.post("/echo", json={"name": "bear"}, base_url="https://example.test")
assert response.status_code == 200
assert response.is_json
assert response.get_json() == {"value": {"name": "bear"}, "secure": True}
get/post/put/patch/delete/options/headとopen(path, method="GET", ...)を使えます。
responseのget_data(as_text=True)は文字列、.data/get_data()はbytesを返します。
| 引数 | 動作 |
|---|---|
headers |
header mapping。名前は大文字小文字を区別しない |
query |
mappingまたはpair list。list値は繰り返しqueryに展開 |
query_string(0.7+) |
str、ASCII bytes、mapping、pair list。queryとの併用不可 |
base_url(0.7+) |
HTTP(S) originのみ。例: https://example.test:8443。path prefixや認証情報は不可 |
content_type(0.7+) |
Content-Typeを指定 |
json |
JSON化する値。非Noneの値はdata/filesと併用不可 |
data |
str、bytes、form mapping。mappingのlist値は繰り返しform値 |
files |
{"file": ("bear.txt", b"hello", "text/plain")}。同名複数fileはtupleのlist |
follow_redirects |
既定False。同じhostの相対/絶対HTTP(S) redirectだけ追跡 |
max_redirects |
既定20。loopや上限超過はRuntimeError |
query/query_stringを渡すとpath内のqueryを置き換えます。json=Noneはbodyなしです。
JSON nullを送る場合はdata="null", content_type="application/json"にします。
303はGET(HEADはHEAD)へ、301/302のGET/HEAD以外もGETへ変更します。307/308はmethodとbodyを保持します。
最終responseの.historyは途中のresponseのtupleです。外部hostへ通信しません。
request contextだけを作る¶
from higuma import Higuma, has_request_context, request, url_for
app = Higuma(__name__, static_folder=None)
@app.get("/bears/<int:bear_id>")
def bear(bear_id):
return {"id": bear_id}
with app.test_request_context("/bears/7", query_string={"name": "higuma"}) as current:
assert request.view_args == {"bear_id": 7}
assert request.endpoint == "bear"
assert current.args["name"] == "higuma"
assert url_for("bear", bear_id=9) == "/bears/9"
assert not has_request_context()
このhelperは上表のrequest構築引数(methodを含む)を受け取り、routing metadataと
型付きpath値を設定します。follow_redirects/max_redirectsはdispatch専用なので受け取りません。
withが返す値はHigumaのRequestです。FlaskのRequestContext wrapperやpush/pop APIではありません。
contextを作るだけではview、middleware、before/after hook、CSRF、session読み込みは実行しません。
SessionMiddlewareが走らないため、sessionを使うテストはtest clientからrequestします。
終了時にはteardown_requestを実行します。独自app contextを作成した場合だけ、
teardown_appcontextも実行します。nested context終了後は外側のrequestとgを復元します。
直接作成したrequestにもcontextを適用できます。
from higuma import Request
with app.request_context(Request({"path": "/manual", "method": "GET"})):
assert request.path == "/manual"
request_contextはWSGI environを受け取りません。また自動でrouteを選択しません。
route情報が必要ならtest_request_contextを使います。
Lifespanとsessionを含むテスト¶
with app.test_client() as client:はstartup/shutdown・lifespanを実行します。
Flaskのclient contextと異なり、最後のrequest contextを保持しません。
request終了後はresponseをassertし、request proxyやgを参照しません。
session・CSRF・Blueprint hooksをまとめて試すには、
examples/flask_lifecycle.pyの実行手順を参照してください。
Cookie jarは簡易な名前と値の保存であり、browserのDomain/Path/Secure/SameSite・期限判定を
完全再現しません。HTTPS、CORS、browserのCookie制約は実browserでも検証します。
repositoryの回帰テスト¶
外部サーバー入口の検証は次を使います。app.test_client()だけではASGI/WSGIの
protocolやtransportを通らないため、それだけで外部サーバー対応の確認にはなりません。
protocol testは標準ライブラリで実行できます(Flask mount比較は任意のcompat extra)。
実通信では組み込み・Uvicorn・wsgirefへ同じアプリを起動し、HTTP/SSE/WSを検証します。
Uvicorn/WS clientのcaseにはasgi extraが必要です。CIではextra付きで実行します。
WSGIの標準WebSocket非対応もHTTPテストで固定します。
compat extraがある場合は同じ共通動作を実Flaskにも実行します。未導入ならFlaskのcaseのみskipします。
server testは別processでRust serverを起動し、CSRF拒否、Unicode JSON、session Cookie、
Blueprint response header、teardownを実HTTPで確認します。終了時にprocessを停止します。
test clientはstream/file/templateをメモリへ展開します。streamingのtiming、切断、backpressure、 WebSocket handshake、proxy、TLSはtest clientだけでは保証できません。対応する実socket testと 公開wheelのfresh install smokeを併用します。