LoginSignup
7
4

More than 5 years have passed since last update.

pythonでfreezegunを使って現在時刻を含む関数を単体テストする方法

Last updated at Posted at 2017-06-22

こんにちはsekitakaです。

今日はdatetime.now()を使用している関数をテストする方法を紹介します。

たとえば次のようなプログラム実行時の次の日を"YYYYMMDD"の文字列を返す関数を作って、その関数をテストしたいとします。

def get_tomorrow():
    now_datetime = datetime.now()
    tomorrow_datetime = now_datetime + timedelta(days=+1)
    tomorrow = tomorrow_datetime.strftime("%Y%m%d")
    return tomorrow

テスト方法

案1

まず簡単に以下のテストコードを書いてみました。しかし見て分かる通り、テストの実行を2017/6/22に行う場合のみ成功します。
これではCIで毎日テストを実施した時にエラーになってしまいます。

class Test(TestCase):
    def test_get_tomorrow(self):
        self.assertEqual("20170623", get_tomorrow())

案2

次に考えたのは期待する値を動的に生成するものです。これならいつテストしてもテストをパスします。
しかし実はget_tomorrowと実質的に同じコードを書いており、テストになっていないような気もします。

class Test(TestCase):
    def test_get_tomorrow(self):
        expect_tomorrow = (datetime.now() + timedelta(days=+1)).strftime("%Y%m%d")
        self.assertEqual(expect_tomorrow, get_tomorrow())

案3

そこでdatetime.now()をMock化して、任意のdatetimeを返す状態にしてget_tomorrowを実行すれば良いのではないかと考えました。そして書いたのが次のコードです。

from mock import Mock
class Test(TestCase):
    def test_get_tomorrow(self):
        datetime.now = Mock(return_value=datetime(year=2017, month=1, day=1))
        self.assertEqual("20170102", get_tomorrow())

期待して実行したところ、ビルトインのdatetimeにattributeをセット出来ないらしく実行できませんでした。

TypeError: can't set attributes of built-in/extension type 'datetime.datetime'

案4(答え)

困っていたところfreezegunというdatetimeモジュールをモック化するライブラリを発見しました。

from freezegun import freeze_time
class Test(TestCase):
    @freeze_time("2017-01-01")
    def test_get_tomorrow_4(self):
        self.assertEqual("20170102", get_tomorrow())

@freeze_time("2017-01-01")の記述によって現在を2017/1/1に固定しています。
よってget_tomorrow()は常に"20170102"を返すことになり、いつテストを実行しても成功することになります。
freeze_timeする日を変更すれば年跨ぎやうるう年で正常にプログラムが動作するかなども確認できそうで便利ですね。

まとめ

いかがでしたでしょうか。pythonのdatetime.now()に依存する関数のテスト方法を紹介しました。
単体テストも一度実行して終わりでなく、CIを回すならいつ実行してもいいようにテストケースを作っておく必要があるのですね。
これからもテスト手法について学んでいきたいと思います。

7
4
1

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
7
4