49

次のようなメソッドを持つクラスのテストを作成しようとしています。

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を使用する例をたくさん読んでいますが、必要なものが見つからず、テストでMockを使用する方法がわかりません。

get_now()の代わりに、それをモックする方が簡単な場合に備えて、メソッドを分離しましたdatetime.datetime.now()が、それでも困惑しています。Mockを使用してこのためのUnitTestを作成する方法について何か考えはありますか?(これはすべてDjango、fwiwにあります。この場合、これが違いを生むかどうかはわかりません。)

4

8 に答える 8

43

あなたはフリーズガンを使うことができます:

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モジュール呼び出しをモックします。

于 2015-05-11T13:36:22.673 に答える
31

渡されたタイムゾーンにローカライズされた特定の日時を返す関数を作成します。

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_nowget_now

于 2012-10-25T16:46:01.040 に答える
5

私は を使用して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。これを再定義して、必要なことを行うことができます。

于 2012-10-25T16:51:15.447 に答える
2

「testfixtures」パッケージのヘルパーを使用して、now() を呼び出している datetime クラスをモックアウトします。

http://packages.python.org/testfixtures/datetime.html#datetimes

そうすれば、すべてのケースをいつでもテストできます。

于 2013-01-16T14:47:05.287 に答える
2

もともとこの質問をした...

@Jocelyn delalande が示唆したように、私は何年もの間フリーズガンを喜んで使用してきました。

別のオプションはpython-libfaketime です。これは、freezegun よりもはるかに高速ですが、Windows では機能せず、少し面倒に聞こえます。

新しいオプションはtime-machineで、3 つのオプションを比較するこのブログ投稿で紹介されています。

于 2020-07-10T15:15:27.730 に答える