紹介
はじめてQiita記事を書きます、よろしくお願いします。
普段はECシステムを担当してます、自分のチームはテストをちゃんと書くのを決めたので、pytest導入をしようと思います。今回pytest導入したプロジェクトはメールテンプレートAPIです。ここのメールテンプレートAPIは、ECサイトで注文後、お客様にメールを届く文面生成処理のAPIです。
従来bashで実装されていたメール文面生成処理をPythonのAPI(Lambdaで実装)に移行した。
- python移行したテストにあたって以下のような課題があった
- レスポンス項目のうちの一つであるメール文面をアサーションする必要があったが、内容が長いためassertを使うと結果が見辛い
- メール文面は注文元ショップ(Yahoo, Amazon...など)とメール種類(注文確認、出荷...など)の組み合わせにより沢山の種類があり、全ての組み合わせに対してテストケースを用意するのは大変
- それぞれの課題について、以下の方法にて解決した
- メール文面のアサーションには、
git diff
コマンドの出力結果などにも用いられている標準ライブラリのdifflibを使ったところ、見慣れた形式で差分比較ができた - 複数データに対するテストケースの定義は、
pytest
のparametetrizeアノテーションを用いた
- メール文面のアサーションには、
pytestの標準test discoveryルール (詳細)
- ファイル名は
test_*.py
や*_test.py
- クラス名は
Test
で始まる必要があり - 関数、クラスのメソッドは先頭にプレフィックス
test_
つける必要があり
Parametrizing
色々パラメーターをテストしたい時に、@pytest.mark.parametrize
は便利です。
この例で、沢山のグループ店舗、メールタイプ、注文番号
をテストしたいので、1個テスト関数を作ればOKです。
手順
# pytestインストール
$ pip install pytest
# pytestインストールできた確認
$ pytest --version
# pytestを実行
# -vは結果を詳細に表示する
$ pytest -v
入力
1_1_2xxx.txt
xxx様
この度は「店舗」をご利用いただき、誠にありがとうございます。
ご注文内容は下記の通りです。test
商品発送後、改めて『商品の発送のお知らせ』メールを送信させていただきます。
コード
test_message.py
from pathlib import Path
import os
import difflib
import pytest
local_path = Path.cwd()
txt_dir = local_path.joinpath('data')
def get_testdata():
"""
`data`フォルダーにファイル名からテストデータを作る
Returns:
list: parametrizeのtestdataとids
"""
testdata = []
testdata_ids = []
for filename_with_path in txt_dir.glob('*_*_*.txt'):
filename = os.path.basename(filename_with_path)
mail_type = filename.split('_')[0]
order_shop = filename.split('_')[1]
order_no = filename.split('_')[2]
testdata.append(tuple((order_shop, mail_type, order_no)))
testdata_ids.append(f'{order_shop}_{mail_type}_{order_no}')
return [testdata, testdata_ids]
testdata = get_testdata()[0]
testdata_ids = get_testdata()[1]
@pytest.mark.parametrize('order_shop, mail_type, order_no',
testdata,
ids=testdata_ids)
def test_mail_message(order_shop: str, mail_type: str, order_no: str):
"""
shell作ったメールテンプレートとpythonのを比較する
Args:
order_shop (str): 店舗
mail_type (str): メールタイプ
order_no (str): 注文番号
"""
# このプログラミングで作成したメールテンプレートを読み込む
fromfile = '''xxx様
この度は「店舗」をご利用いただき、誠にありがとうございます。
ご注文内容は下記の通りです。
商品発送後、改めて『商品の発送のお知らせ』メールを送信させていただきます。'''
# shellで作成したメールテンプレートを読み込む
compare_file = local_path.joinpath('data').joinpath(
f'{order_shop}_{mail_type}_{order_no}')
if compare_file.is_file():
with open(compare_file) as f:
tofile = f.read()
# 比較を実施
diff = difflib.unified_diff(fromfile.splitlines(keepends=True),
tofile.splitlines(keepends=True),
fromfile='python-mail-api',
tofile='shell-mail-api')
diff_str = ''.join(diff)
print(diff_str)
assert not diff_str