
Pandas, OpenPyXL で pytest の手習い
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
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






