次のようなメソッドを持つクラスのテストを記述しようとしています。
_import datetime
import pytz
class MyClass:
def get_now(self, timezone):
return datetime.datetime.now(timezone)
def do_many_things(self, tz_string='Europe/London'):
tz = pytz.timezone(tz_string)
localtime_now = self.get_now(tz)
...
return things
_
私はそれをテストしたいので、datetime.datetime.now()
呼び出しが予測可能なものを返すことを確認する必要があります。
私はテストで Mock を使用する多くの例を読んでいますが、必要なものがまったく見つからず、テストでそれを使用する方法を見つけることができません。
get_now()
ではなくdatetime.datetime.now()
メソッドをモックしやすいように分離しましたが、それでも困惑しています。 Mockを使用してこのためのUnitTestsを作成する方法についての考えはありますか? (これはすべてDjangoのfwiwにあります。これがこの場合に違いをもたらすかどうかはわかりません。)
渡されたタイムゾーンにローカライズされた特定の日時を返す関数を作成します。
import mock
def mocked_get_now(timezone):
dt = datetime.datetime(2012, 1, 1, 10, 10, 10)
return timezone.localize(dt)
@mock.patch('path.to.your.models.MyClass.get_now', side_effect=mocked_get_now)
def your_test(self, mock_obj):
# Within this test, `MyClass.get_now()` is a mock that'll return a predictable
# timezone-aware datetime object, set to 2012-01-01 10:10:10.
そうすれば、結果のタイムゾーン対応の日時が正しく処理されているかどうかをテストできます。他の場所の結果は正しいタイムゾーンを表示するはずですが、予測可能な日付と時刻になります。
mocked_get_now
をモックするときの副作用として、get_now
関数を使用します。コードがget_now
を呼び出すたびに、その呼び出しはmock
、およびによって記録され、mocked_get_now
が呼び出され、その戻り値がget_now
の呼び出し元。
freezegun を使用できます:
from freezegun import freeze_time
def test():
assert datetime.datetime.now() != datetime.datetime(2012, 1, 14)
with freeze_time("2012-01-14"):
assert datetime.datetime.now() == datetime.datetime(2012, 1, 14)
assert datetime.datetime.now() != datetime.datetime(2012, 1, 14)
基本的にdatetime
モジュール呼び出しをモックします。
私はdate
を使用していますが、同じ考え方がdatetime
でも機能するはずです。
class SpoofDate(date):
def __new__(cls, *args, **kwargs):
return date.__new__(date, *args, **kwargs)
...
from mock import patch
@patch('some.module.date', SpoofDate)
def testSomething(self):
SpoofDate.today = classmethod(lambda cls : date(2012, 9, 24))
どこ some.module
インポートdate
。パッチは、インポートされたdate
をSpoofDate
に置き換えます。これを再定義して、好きなようにすることができます。
'testfixtures'パッケージのヘルパーを使用して、今呼び出している日時クラスをモックアウトします()。
http://packages.python.org/testfixtures/datetime.html#datetimes
このようにして、すべてのケースをいつでもテストできます。
Unittest.mockのパッチを使用する
from unittest.mock import patch
@patch('MyClass.datetime')
def test_foo(self, mock_datetime):
mock_datetime.datetime.now.return_value = datetime.datetime(2019, 5, 7) #SOME_MOCKED_DATE
クラスにのみインポートされるdatetimeモジュールをオーバーライドしています
テストを作成するクラス:
import datetime
class MyClass:
def foo():
localtime_now = datetime.datetime.now(timezone)
モックしやすくするためだけにget_now()メソッドとして分離する必要はありません。