5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

pytestでdifflibを使ってみた (例付き)

Posted at

紹介

はじめてQiita記事を書きます、よろしくお願いします。

普段はECシステムを担当してます、自分のチームはテストをちゃんと書くのを決めたので、pytest導入をしようと思います。今回pytest導入したプロジェクトはメールテンプレートAPIです。ここのメールテンプレートAPIは、ECサイトで注文後、お客様にメールを届く文面生成処理のAPIです。

従来bashで実装されていたメール文面生成処理をPythonのAPI(Lambdaで実装)に移行した。

  • python移行したテストにあたって以下のような課題があった
    1. レスポンス項目のうちの一つであるメール文面をアサーションする必要があったが、内容が長いためassertを使うと結果が見辛い
    2. メール文面は注文元ショップ(Yahoo, Amazon...など)とメール種類(注文確認、出荷...など)の組み合わせにより沢山の種類があり、全ての組み合わせに対してテストケースを用意するのは大変
  • それぞれの課題について、以下の方法にて解決した
    1. メール文面のアサーションには、git diffコマンドの出力結果などにも用いられている標準ライブラリのdifflibを使ったところ、見慣れた形式で差分比較ができた
    2. 複数データに対するテストケースの定義は、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

結果

image.png
メールの差分を見えます!

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?