前回の記事では、FlaskでCSVを受け取ってpandasのDataFrame化するエンドポイントを作成しました。
今回はpytestを使ってそのエンドポイントをテストしてみたいと思います。
環境
Python==3.8.1
Flask==1.1.1
Werkzeug==1.0.0
目的
Flaskは最小限の機能だけを持つWebフレームワークですが、テスト機能がきちんと存在します。
そのテスト機能を使いこなして開発効率を向上させることが出来ますが、前回のようにCSVを受け付けるエンドポイントもテストもちろんテスト出来るので、その備忘録となります。
実際のコード
ディレクトリ構成のイメージ
1 2 3 4 5 6 |
my_project ├ app │ └ main.py └ test ├ confest.py └ test_app.py |
pytest + Flaskの基本
Flaskにはテスト用のクライアントを作成する機能が付いているので、その機能を活用してあげます。
なお、with構文を使わないとうまくいかない模様です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import pytest from main import app as api @pytest.fixture def app(): # Pycharmのテストでログをコンソールに出力するための設定 import logging logging.basicConfig(level=logging.DEBUG) # DB初期化等の前処理 # Pycharmでデバッガにエラーを拾わせるための設定 api.config['PROPAGATE_EXCEPTIONS'] = True yield api # DB削除等の後処理 @pytest.fixture def client(app): with app.test_client() as client: return client |
以下のようにfixtureで作成したテストクライアントから、getやpostメソッドを呼び出すことでテストが行えます。
直感的で素晴らしいですね。requestsからリクエストを送信する際と似ているのでPython使いにとって有難い作りになってます。
1 2 3 |
def test_sample(client): res = client.post('/user/adress', ) assert assert res.status_code == 200 |
CSVをpostで送信する
今回は一度DataFrameとしてCSVを読み込む形をとりました。
不要データの削除や、意図的なエラー発生のための事前にデータの加工が出来るので、DataFrameに一度落とす形が無難かと思います。
さて、client.postでデータを送信しますが、CSVとして認識させるためにはその際に一手間必要です。
- content_typeにmultipart/form-dataを指定
- BytesIOにしてからデータを送信する。
完成系は以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import io import pandas as pd def test_post_csv(client): df = pd.read_csv('test_data.csv') # index=Falseは必要有無に応じて csv_str = df.to_csv(index=False) client.post( '/', content_type='multipart/form-data', data={ 'data': (io.BytesIO(csv_str.encode()), 'test_data.csv') } ) |
BytesIOにしてからデータを送信するために、一度str型でcsvを出力(to_csvで出力先を指定しない場合はstr型で出力されます)し、その文字列をencodeしてbytes型にしています。
ちょっと手間取ってしまいましたが、これで快適なテスト生活に一歩近づけたような気がします。まだまだこれからですがね…。