LoginSignup
9
3

More than 3 years have passed since last update.

pytest でも datetime.datetime.now() を mock したい!

Last updated at Posted at 2020-03-11

TL; DR

こんな感じでモックすると、datetime.datetime.now() をモックできます。この方法だと datetime.datetime の他の関数はそのまま使うことができます。

from unittest.mock import MagicMock

def test_mocking_datetime_now(monkeypatch):
    datetime_mock = MagicMock(wraps=datetime.datetime)
    datetime_mock.now.return_value = datetime.datetime(2020, 3, 11, 0, 0, 0)
    monkeypatch.setattr(datetime, "datetime", datetime_mock)

背景

現在時刻を取得する処理をテストするときに、datetime.datetime.now() をモックしたいことがあります。このとき、単純に monkeypatch.setattrでモックしようとしても、datetime.datetime.now() は built-in のため、モックすることができません。

import datetime
from unittest.mock import MagicMock

FAKE_NOW = datetime.datetime(2020, 3, 11, 0, 0, 0)

def test_mocking_datetime_now_incorrect(monkeypatch):
    monkeypatch.setattr(datetime.datetime, "now", MagicMock(return_value=FAKE_NOW)
>       monkeypatch.setattr(datetime.datetime, "now", MagicMock(return_value="hoge"))
E       TypeError: can't set attributes of built-in/extension type 'datetime.datetime'

そこで MagicMock(wraps=datetime.datetime)

そこで、MagicMock(wraps=...) を利用します。wrap 引数にモックするオブジェクトを指定して、通常のメソッドを wrap したオブジェクトに流しつつ、必要なメソッドをモックすることができます。

from unittest.mock import MagicMock

def test_mocking_datetime_now(monkeypatch):
    # now() だけをモックした datetime_mock を作成
    datetime_mock = MagicMock(wraps=datetime.datetime)
    datetime_mock.now.return_value = datetime.datetime(2020, 3, 11, 0, 0, 0)  # これで now() をモック

    # datetime.datetime を datetime_mock で置き換え
    monkeypatch.setattr(datetime, "datetime", datetime_mock)

    # 以下、datetime.datetime.now() を使うテスト

余録

stackoverflow のトップ回答 がイケてなかったのでムシャクシャして(回答して)やった。反省はしてない。

トップ回答の方法だと datetime.datetime の他のメソッドが呼べないんですよね。こちらの方法なら、datetime.datetime.fromisoformat() とか、他のメソッドは通常通りに呼べるぞ、と。

ちなみに別解としては、 pytest-freezegun を使うというのがあり、こっちのほうがメジャーっぽいですね。参考: Pytest現在時刻テスト(日時固定) - Qiita

9
3
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
9
3