この記事を書いた経緯
pytestで「明日の日時を取得して特定のフォーマットに整形する。」という関数(関数hogeとします)のテストを書く場面がありました。
しかし、関数の実行結果が現在日時に依存するため実行結果を検証できない問題が発生しました。(hogeの実行日時が08/01の場合⇒08/02, 08/10の場合⇒08/11が返る)
この問題を解決するためにpytest-freezegunというパッケージを利用します。
pytest-freezegunはテスト実行時に日時を指定することができるpytest用のパッケージです。
実行環境
- Ubuntu20.04
- Python3.8.10
- pytest6.2.5
- pytest-freezegun0.4.2
利用方法
インストール手順
※ Pythonとpytestはインストール済みとします。
pip install pytest-freezegun
正しくインストールできたことを確認します。
pip show pytest-freezegun
Name: pytest-freezegun
Version: 0.4.2
Summary: Wrap tests with fixtures in freeze_time
Home-page: https://github.com/ktosiek/pytest-freezegun
Author: Tomasz Kontusz
Author-email: tomasz.kontusz@gmail.com
License: MIT
Location: /usr/local/lib/python3.8/dist-packages
Requires: freezegun, pytest
Required-by:
使用例
本来はテスト対象の関数とテストコードは別のファイルに書きますが、可読性を優先して同じファイルに書きます。
import pytest
import typing
from datetime import datetime, timedelta
# テスト対象の関数
def hoge() -> str:
# 翌日の日時を取得してm/d(a)という形式に整形する
tomorrow: datetime = datetime.now() + timedelta(days=1)
tommorow_str: str = tomorrow.strftime("%m/%d (%a)")
# 変換後の日時を使って戻り値を作る。
headline: str = f"{tommorow_str} の天気予報です。"
return headline
# テストメソッド
# 日時のフォーマットは2022/08/14や20220814でも問題ありません。
@pytest.mark.freeze_time("2022-08-14")
def test_hoge():
headline: str = hoge()
assert headline == "08/15 (Mon) の天気予報です。"
test.pyメソッドをテストします。
テストが通ればOKです。(rootディレクトリやそのほかのpluginはご自身の環境に合わせて読みかえてください。)
捕捉
サンプルコードではデコレータを使って日時を固定していますが、freezer
フィクスチャを用いてテストメソッド内で日時を固定することもできます。
# テスト対象関数は省略します
def test_hoge2(freezer):
freezer.move_to("2022-08-14")
headline: str = hoge()
assert headline == "08/15 (Mon) の天気予報です。"
また、pytest-freezegunで固定された日時はそのメソッド内のみで有効です。
## 2022/08/14にテストを実行します。
def test_hoge2(freezer):
freezer.move_to("2022-08-11")
headline: str = hoge()
assert headline == "08/12 (Fri) の天気予報です。"
def test_hoge3():
headline: str = hoge()
assert headline == "08/12 (Fri) の天気予報です。"
test_hoge3()内では現在時刻 = テスト実行日時であるため、テストが失敗します。
まとめ
pytest-freezegunを使ってテスト実行時の日時に関わらず、テストを通す方法を紹介しました。
日時に限らずテスト実行時の環境(天気・外部API等)への依存をいかに減らすかということがテストコードにおいては重要です。