Имитация прохождения времени в unittesting
Я построил систему клиентских платежей CMS + для клиента, и мне нужно получить более строгие результаты при тестировании.
Я сохраняю все свои данные в ORM Django и имею множество задач Celery, которые выполняются с разными интервалами, что гарантирует отправку новых счетов-фактур и напоминаний о счетах и сокращение доступа, когда пользователи не оплачивают свои счета-фактуры.
Например, я хотел бы иметь возможность запускать тест, который:
-
Создает нового пользователя и создает счет за X дней доступа к сайту
-
Имитирует прохождение X + 1 дня и выполняет все задания, которые я установил в Celery.
-
Проверяет, что пользователю был выдан новый счет за другие X дней.
Подход KISS, к которому я придумал, - это все тестирование на отдельной машине и фактическое манипулирование датой/временем на уровне ОС. Таким образом, тестирование script:
-
Установите системную дату на день 1
-
Создайте нового пользователя и сгенерируйте первый счет за X дней доступа
-
Затем введите системную дату 1 день. Запустите все задания по сельдерею. Повторяйте до тех пор, пока X + 1 день не пройдет "
-
Убедитесь, что новый счет выставлен
Это немного неуклюже, но я думаю, что это может сработать. Любые другие идеи о том, как это сделать?
Ответы
Ответ 1
Вы можете использовать mock, чтобы изменить возвращаемое значение функции, используемой вами для получения времени (datetime.datetime.now
например).
Существуют различные способы сделать это (см. макет документации), но вот один из них:
import unittest
import datetime
from mock import patch
class SomeTestCase(unittest.TestCase):
def setUp(self):
self.time = datetime.datetime(2012, 5, 18)
class fakedatetime(datetime.datetime):
@classmethod
def now(cls):
return self.time
patcher = patch('datetime.datetime', fakedatetime)
self.addCleanup(patcher.stop)
patcher.start()
def test_something(self):
self.assertEqual(datetime.datetime.now(), datetime.datetime(2012, 5, 18))
self.time = datetime.datetime(2012, 5, 20)
self.assertEqual(datetime.datetime.now(), datetime.datetime(2012, 5, 20))
Поскольку мы не можем напрямую заменить datetime.datetime.now
, мы создаем поддельный класс datetime, который делает все одинаково, за исключением возвращения постоянного значения, когда он теперь вызывается.
Ответ 2
Без использования специальной макетной библиотеки я предлагаю подготовить код для макета (возможно, с помощью глобальной переменной). В режиме макета вместо вызова нормальной функции времени (например, time.time() или любого другого) вы можете вызвать функцию времени макета, которая возвращает все, что вам нужно в вашем специальном случае.
Я бы проголосовал за изменение системного времени. Это не похоже на unit test, а скорее как функциональный тест, поскольку он не может выполняться параллельно ни с чем другим на этой машине.