2011-07-04 12 views
7

特定の曜日(たとえば、月の最初の日曜日、月の3番目の金曜日)に再発するイベントをトラッキングしています。イベントの曜日を格納するDayOfWeekモデルがあります。このメソッドには、next_day_of_weekというメソッドが含まれており、指定されたイベントインスタンスが設定されている曜日の次の日付に設定された日付オブジェクトを返します(これは、イベントの次回の発生を把握するのに役立ちます)。日曜日2011年7月3日に例えばmockingを使用してnext_day_of_week関数をテストする方法

、:

  • のDayOfWeekを持つオブジェクトの場合は、日曜日に設定し、next_day_of_week 2011年7月3日を返します。
  • DayOfWeekを月曜日に設定すると、2011年7月4日に返されます。
  • DayOfWeekが土曜日に設定されている場合、2011年7月9日に返されます。

など。私は単体テストを書いています(私の初めてのことですが、私はこれについてかなり新しいことを言及しましたか?)、そしてこの方法をテストする方法について私の頭を覆そうとしています。私は何かを模倣する必要があることを知っているが、私は何がよく分からない。この質問は、私が求めているものをでやっている:Python: Trying to mock datetime.date.today() but not working

をだから私はtests.pyでdatetime.dateをモックとしてみてください。

class FakeDate(date): 
"A fake replacement for date that can be mocked for testing." 
    def __new__(cls, *args, **kwargs): 
     return date.__new__(date, *args, **kwargs) 

そして、私はモッククラスでパッチ適用、私のテストケースを作成しますそして2011年7月3日に、今日の設定:

class TestDayOfWeek(TestCase): 
    """Test the day of the week functions.""" 

    @mock.patch('datetime.date', FakeDate) 
    def test_valid_my_next_day_of_week_sameday(self): 
     from datetime import date 
     FakeDate.today = classmethod(lambda cls: date(2011, 7, 3)) # July 3, 2011 is a Sunday 
     new_day_of_week = DayOfWeek.objects.create() 
     new_day_of_week.day = "SU" 
    self.assertEquals(new_day_of_week.my_next_day_of_week(), date(2011, 7, 3)) 

参考のため、ここではモデルクラスは次のとおりです。

class DayOfWeek(ModelBase): 
""" 
Represents a day of the week (on which an event can take place). 
Because the dates of these events are often designated by terms like 'first Monday' 
or 'third Friday', this field is useful in determining on which dates individual 
readings take place. 
""" 

# The pk in the db is 1-indexed (Monday=1, Tuesday=2, etc), but python's days 
# of the week are 0-indexed if you use .weekday(), so we are using .isoweekday() 
# instead. This list is used in my_next_day_of_week. 
days =[ 'No day', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 
     'Sunday' ] 

DAYS_OF_WEEK_CHOICES = (
('MO', days[1]), 
('TU', days[2]), 
('WE', days[3]), 
('TH', days[4]), 
('FR', days[5]), 
('SA', days[6]), 
('SU', days[7]), 
) 

day = models.CharField(max_length=2, choices=DAYS_OF_WEEK_CHOICES) 

def __unicode__(self): 
    for daypair in self.DAYS_OF_WEEK_CHOICES: 
     if self.day in daypair: 
      return daypair[1] 

    # This shouldn't happen 
    raise InvalidDayOfWeekError 

# my_next_day_of_week returns a datetime equal to the start (midnight+min) of the next day that is this instance's day of the week. 
# It doesn't know what time the event is, so if today is the day of the week the event falls on, 
# it simply returns today. 
def my_next_day_of_week(self): 
    """ 
    Returns a datetime equal to the start of the next day that is this instance's day of the week. 
    """ 

    today_day = date.today().isoweekday() # Find the number of the current day of the week 
    reading_day = self.days.index(self.__unicode__()) # Find the number of the instance's day of the week 
      # There is probably a more pythonic way to do this next part 
    next_day = date.today() # start with next day = today 
    while next_day.isoweekday() != reading_day: 
     next_day = next_day + timedelta(1) 

    return next_day 

したがって、私はDayOfWeekインスタンスがmock datetime.dateを使用していないように見えるので、djangoのテストランナーを実行するとテストが失敗し、今日の実際の日が表示されます。私の読書からは、モックは試験方法の中にのみ存在し、前後には存在しないことが理解される。しかし、これはまた、テストメソッド内からインスタンス化/呼び出されるオブジェクト/メソッドには存在しないことを意味しますか?次に、それをどのように使用していますか?私はそれが問題だとは思わないが、むしろパッチを当てるときに何か間違っていると思う。たぶん名前空間の問題?私はこれを読んでいます:http://www.voidspace.org.uk/python/mock/patch.html#id2 私はそれを修正しようとしていますが、私は成功するとこれを編集するつもりですが、それまでのポインタが評価されるまで!

EDIT:datetime.dateの代わりに私のモデルでdatetime.datetimeを使用していることを認識しました。私はそれを修正し、上記のコードを編集しましたが、使用されていない擬似クラスの根本的な問題は残っています。

答えて

9

それがわかりました。質問は本当に「パッチを当てる場所」でした。その答えは、(this page)にリンクしているMockのドキュメントを調べて得たものです。解決策はそうのように、このアプリのためのモデルを含むモジュールの名前空間で日付クラスをモックすることでした:

@mock.patch('series.models.date', FakeDate) # mock out the date class in the module that has already imported it via from datetime import date, i.e. series.models (app_name.module_name) 
def test_valid_my_next_day_of_week_sameday(self): 
    from datetime import date 
    FakeDate.today = classmethod(lambda cls: date(2011, 7, 3)) # July 3, 2011 is a Sunday 
    new_day_of_week = DayOfWeek.objects.create() 
    new_day_of_week.day = "SU" 
    self.assertEquals(new_day_of_week.my_next_day_of_week(), date(2011, 7, 3)) 

うまくいけば、これは他の誰かに助けになることができます!

+2

私は[変更可能なクラスを嘲笑/パッチすることについてのより長い説明を書いた](http://williamjohnbert.com/2011/07/how-to-unit-testing-in-django-with-mocking-and-patching/)in他の人には役に立ちます。 – sandinmyjoints

0

あなたが必要とする答えはthe other postに含まれていると思います。私はあなたのニーズに合わせて書き直しました。

import datetime 
class FakeDate(datetime.date): 
    @classmethod 
    def today(cls): 
     return cls(2011, 7, 3) 
datetime.date = FakeDate 

class TestDayOfWeek(TestCase): 
    """Test the day of the week functions.""" 

    def test_valid_my_next_day_of_week_sameday(self): 
     new_day_of_week = DayOfWeek.objects.create() 
     new_day_of_week.day = "SU" 
     self.assertEquals(new_day_of_week.my_next_day_of_week(), date(2011, 7, 3)) 
+0

あなたはそうです、これはこの場合でも有効です。しかし、datetime.dateは残りのテストメソッドのすべてについて嘲笑されるでしょう。私は@モックデコレータソリューションは少し良いと思う - それはそれが呼び出されている特定のメソッドのためのモックアウト。 – sandinmyjoints

関連する問題