Pandas, OpenPyXL で pytest の手習い
pytestの使い方を学びます。テストケースには、個人的に直近で利用していたPandas, OpenPyXLを利用したいと思います。 手順は、pytest を参考にさせていただきます。
環境/前提
こちらの記事と同様の環境を利用します。
なお、今回は追加で以下のパッケージが必要です。
- numpy 1.23.3
- pytest 7.1.3
テストの書き方/テスト実行(アサーションチェック)
まずは、単純なテストケースを利用し、pytestの書き方を学びます。
pytest は test_ で始まるファイル・関数を単体テストのコードとみなします
テストの書き方
pandas Testingのassert_series_equal
関数は、デフォルトでdtypeまで確認してくれます(第3引数: check_dtype=True1)。
テストケースは、Book1.xlsxファイルの2行目(A:E)に入っているデータが期待したものになっているかのチェック
です。
import pytest import numpy as np import pandas as pd from pandas.testing import assert_series_equal import openpyxl def test_read_excel(): actual = pd.read_excel('Book1.xlsx', sheet_name='Sheet1', usecols="A:E", dtype = { 'メールアドレス1(必須)': 'string', 'メールアドレス2(任意)': 'string', 'メールアドレス3(任意)': 'string' }) assert_series_equal(actual['ID'], pd.Series([12345], dtype=np.int64, name='ID')) assert_series_equal(actual['日付'], pd.Series([pd.to_datetime('2022/08/31')], dtype='datetime64[ns]', name='日付')) assert_series_equal(actual['メールアドレス1(必須)'], pd.Series(['shiraishi@example.com'], dtype='string', name='メールアドレス1(必須)')) assert_series_equal(actual['メールアドレス2(任意)'], pd.Series(['shiraishi@example.com'], dtype='string', name='メールアドレス2(任意)')) assert_series_equal(actual['メールアドレス3(任意)'], pd.Series(['shiraishi@example.com'], dtype='string', name='メールアドレス3(任意)'))
$ pytest test_xl_test.py ======================================================================================== test session starts ========================================================================================= platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0 rootdir: /Desktop/test_python collected 1 item test_xl_test.py . [100%] ========================================================================================= 1 passed in 0.61s ==========================================================================================
パラメータ化したテスト
次に@pytest.mark.parametrize
デコレータを使います。
デコレータは、テストで使用する値をパラメータとして持つことができます。初めの引数(expected)は、テスト関数に渡すパラメータの引数名を指定することができます。
テストケースは、Book1.xlsxファイルの2行目1列(A2)に入っている'ID'が期待したものになっているかのチェック
です。
import pytest import numpy as np import pandas as pd from pandas.testing import assert_series_equal import openpyxl @pytest.mark.parametrize(('expected'), [ (pd.Series([12345], dtype=np.int64, name='ID')), ]) def test_read_excel_2(expected): actual = pd.read_excel('Book1.xlsx', sheet_name='Sheet1', usecols="A:E", dtype = { 'メールアドレス1(必須)': 'string', 'メールアドレス2(任意)': 'string', 'メールアドレス3(任意)': 'string' }) assert_series_equal(actual['ID'], expected)
$ pytest test_xl_test.py ======================================================================================== test session starts ========================================================================================= platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0 rootdir: /Desktop/test_python collected 2 items test_xl_test.py .. [100%] ========================================================================================= 2 passed in 0.63s ==========================================================================================
フィクスチャ
最後にフィクスチャを利用します。
フィクスチャでは、テスト関数を実行する前の前処理を記述することができます。今回は、前処理としてBook1.xlsxの2行目(A:E)のデータを書き換えます。
テストケースは、Book1.xlsxファイルの2行目1列(A2)に入っている'ID'が期待したもの(書き変わった値)になっているかのチェック
です。
import pytest import logging import numpy as np import pandas as pd from pandas.testing import assert_series_equal import openpyxl @pytest.fixture def xl_name() -> str: wb = openpyxl.load_workbook('Book1.xlsx') ws = wb["Sheet1"] for i, values in enumerate([['55555', '2022/09/30', 'shiraishi@example.com', 'shiraishi@example.com', 'shiraishi@example.com']]): for j, value in enumerate(values): if value is None: continue ws.cell(row=2+i, column=1+j, value=value) wb.save('Book1.xlsx') yield 'Book2.xlsx' def test_read_excel_3(xl_name): actual = pd.read_excel(xl_name, sheet_name='Sheet1', usecols="A:E", dtype = { 'メールアドレス1(必須)': 'string', 'メールアドレス2(任意)': 'string', 'メールアドレス3(任意)': 'string' }) assert_series_equal(actual['ID'], pd.Series([55555], dtype=np.int64, name='ID'))
$ pytest test_xl_test.py ======================================================================================== test session starts ========================================================================================= platform darwin -- Python 3.10.6, pytest-7.1.3, pluggy-1.0.0 rootdir: /Desktop/test_python collected 3 items test_xl_test.py ... [100%] ========================================================================================= 3 passed in 0.64s ==========================================================================================
所感
昔、xSpec系のテストを学ぶ機会がありました2。xUnit系のテストをあまり書いた経験がなかったのですが、pytestは、このような良い指南書もあり、入門には良いテストライブラリだと感じました。次のステップとしては、どのように考え、どのようなテストを行うか、やテストダブルのおさらいをしたいと思います。以上、pytest入門でした。
参考
- pytest
- BUG: dtype not working with datetime64 #34928