РЕДАКТИРОВАТЬ : Так как мой ответ является принятым ответом здесь, я обновляю его, чтобы все знали, что тем временем был создан лучший способ, библиотека freezegun: https://pypi.python.org/pypi/freezegun. Я использую это во всех моих проектах, когда я хочу влиять на время в тестах. Посмотрите на это.
Оригинальный ответ:
Замена таких внутренних вещей всегда опасна, поскольку может иметь неприятные побочные эффекты. Так что вы действительно хотите, чтобы патч обезьяны был как можно более локальным.
Мы используем превосходную библиотеку-макет Майкла Фоорда: http://www.voidspace.org.uk/python/mock/, в которой есть @patch
декоратор, который исправляет определенные функции, но исправление обезьяны живет только в рамках функции тестирования, и все автоматически восстанавливается после функция выходит за пределы своей области.
Единственная проблема заключается в том, что внутренний модуль datetime
реализован на C, поэтому по умолчанию вы не сможете обезьяна его исправить. Мы исправили это, сделав нашу собственную простую реализацию, которую можно смоделировать.
Общее решение выглядит примерно так (например, функция валидатора, используемая в проекте Django для проверки того, что дата находится в будущем). Имейте в виду, я взял это из проекта, но вынул несущественные вещи, так что на самом деле вещи могут не сработать при копировании, но я понял, я надеюсь:)
Сначала мы определим нашу собственную очень простую реализацию datetime.date.today
в файле с именем utils/date.py
:
import datetime
def today():
return datetime.date.today()
Затем мы создадим юнит-тест для этого валидатора в tests.py
:
import datetime
import mock
from unittest2 import TestCase
from django.core.exceptions import ValidationError
from .. import validators
class ValidationTests(TestCase):
@mock.patch('utils.date.today')
def test_validate_future_date(self, today_mock):
# Pin python's today to returning the same date
# always so we can actually keep on unit testing in the future :)
today_mock.return_value = datetime.date(2010, 1, 1)
# A future date should work
validators.validate_future_date(datetime.date(2010, 1, 2))
# The mocked today's date should fail
with self.assertRaises(ValidationError) as e:
validators.validate_future_date(datetime.date(2010, 1, 1))
self.assertEquals([u'Date should be in the future.'], e.exception.messages)
# Date in the past should also fail
with self.assertRaises(ValidationError) as e:
validators.validate_future_date(datetime.date(2009, 12, 31))
self.assertEquals([u'Date should be in the future.'], e.exception.messages)
Окончательная реализация выглядит следующим образом:
from django.utils.translation import ugettext_lazy as _
from django.core.exceptions import ValidationError
from utils import date
def validate_future_date(value):
if value <= date.today():
raise ValidationError(_('Date should be in the future.'))
Надеюсь, это поможет