minimockでdatetime.date.todayのモック

最近これ系のことばかり書いてます。

pythonでdatetime.dateをpatchする
datetime.dateをpatchする話の続きとisinstanceのオーバーライド
datetime.date.todayの結果をfreezegunを使って固定する


以下はうまくいきませんが、minimockでできないかって試してみたときのメモです。

import datetime
from unittest import TestCase
from dateutil.relativedelta import relativedelta
from minimock import Mock, restore


class DateTodayMockTest(TestCase):
    def setUp(self):
        datetime.date.today = Mock("datetime.date.today",
                                   returns=datetime.date(2014, 1, 1))

    def tearDown(self):
        restore()

    def test_today(self):
        today = datetime.date.today()
        self.assertEquals(today.year, 2014)
        self.assertEquals(today.month, 1)
        self.assertEquals(today.day, 1)
        tomorrow = today + relativedelta(days=1)

        self.assertEquals(tomorrow.year, 2014)
        self.assertEquals(tomorrow.month, 1)
        self.assertEquals(tomorrow.day, 2)

        day_after_day = tomorrow + relativedelta(days=1)
        self.assertEquals(day_after_day.year, 2014)
        self.assertEquals(day_after_day.month, 1)
        self.assertEquals(day_after_day.day, 3)

わかる人はすぐにわかると思いますが、どうなるかというと、以下のエラーになります。

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


なんとかminimockでできないかなと思ってこんなのも試してみてました。

import sys
import datetime
from unittest import TestCase
from dateutil.relativedelta import relativedelta
from minimock import Mock, restore


def get_today():
    return datetime.date.today()

class DateTodayMockTest3(TestCase):
    def setUp(self):
        current_module = sys.modules[__name__]
        current_module.get_today = Mock("get_today",
                                        returns=datetime.date(2014, 1, 1))

    def tearDown(self):
        restore()

    def test_today(self):

        today = get_today()
        self.assertEquals(today.year, 2014)
        self.assertEquals(today.month, 1)
        self.assertEquals(today.day, 1)
        tomorrow = today + relativedelta(days=1)

        self.assertEquals(tomorrow.year, 2014)
        self.assertEquals(tomorrow.month, 1)
        self.assertEquals(tomorrow.day, 2)

        day_after_day = tomorrow + relativedelta(days=1)
        self.assertEquals(day_after_day.year, 2014)
        self.assertEquals(day_after_day.month, 1)
        self.assertEquals(day_after_day.day, 3)

不恰好ですが、これは一応うまくいきます。
テストで差し替えられるようにするためだけに、datetime.date.todayを呼び出すだけの関数を定義してます。