ユニットテストを書くとき、ストレージへの書き出し状況が意図通りであるという点を見たい場合があります。
それを簡単にするために、ディレクトリツリーの現在の状況をMappingとして読み出せるクラスを作りました。ライブラリにしてPyPIに出すほどではない規模なのでここにコード書いちゃいますね。ご自由にお使いください。
これで、 assert PathMapping(tmp_dir) == {'xx': b'yyyyyy'}
なんていう簡単な式でストレージ書き出しを検証できるようになります。パラメータ化テストならこの右辺をパラメータ化できるので複雑な書き出しがあるモジュールのテストでもパラメータ化していろんな動作条件での出力を簡潔な記述で網羅できるようになりますね。
class PathMapping(Mapping):
"""
ディレクトリパスを再帰的なマッピングとして扱う
(文字列をキーに、ディレクトリはマッピング、ファイルはbytes)
例:
my_home
├ foo
│ └ bar.txt (内容は "some content")
└ baz.txt (内容は "another content")
というディレクトリ構造のとき、以下の等式が成立
PathMapping(Path('my_home')) == {
'foo': {
'bar.txt: b'some content\n'
},
'baz.txt': b'another content\n'
}
"""
def __init__(self, path: Path):
self._path = path
def __getitem__(self, k: str):
child = (self._path / k)
if child.is_dir():
return PathMapping(child)
elif child.is_file():
return child.read_bytes()
else:
raise KeyError
def __len__(self) -> int:
return len(list(self._path.iterdir()))
def __iter__(self) -> Iterator[str]:
for child in self._path.iterdir():
yield child.name
このクラスのオブジェクトが吐き出すkey-valueデータはオブジェクト生成時点のものではなく、今現在のディレクトリツリー状況です。
そのことがどう生きてくるかというと、pytestのこんなfixtureを作る場合です。
@fixture
def mock_なんかストレージに書き出すモジュール(monkeypatch):
"""
このfixtureオブジェクトそのものをMappingとしてアクセスすると書き出し結果がみられます
"""
with TemporaryDirectory as tmp_dir:
... # 「なんかストレージに書き出すモジュール」 が tmp_dir に書き出すように
... # monkeypatchでいろいろ乗っ取っている
yield PathMapping(Path(tmp_dir))
こうしておくと、ユニットテスト本文側では
def test_XXX(mock_なんかストレージに書き出すモジュール):
... # ターゲットを呼び出している
... # ターゲットは「なんかストレージに書き出すモジュール」を叩いている
# 検証:想定通り書き出されていること
assert mock_なんかストレージに書き出すモジュール == {'xx': b'yyyyyy'}
と書けます。PathMappingオブジェクトを作った時点ではなく、assertのところまで来た時点でのディレクトリツリー状況が読み出せていますので、こういうことができます。