Naota
Фев. 7, 2011 15:52:18
Как можно эмулировать работу времени для тестов?
Андрей Светлов
Фев. 7, 2011 17:42:59
monkey patch на time.sleep
Главное, в tearDown не забудьте обратно вернуть.
Naota
Фев. 8, 2011 10:40:02
Тогда нужен патч всех библиотек, использующих время. Смысл не обнулить time.sleep, а передвинуть им время, не затрачивая это самое время. Может стоит подумать над сменой системного времени вручную. Какие ещё варианты могут быть?
Андрей Светлов
Фев. 8, 2011 10:45:06
Вынести все использование времени в отдельную, вашу собственную библиотеку. Патчить ее.
Если же ваши библиотеки не вами писаны - то мокеры должны встраиваться перед ними.
Без конкретных примеров помочь не могу, извините.
ziro
Фев. 8, 2011 10:52:54
А действительно ли Вам нужно передвигать время? Может достаточно в тесте переписать зависящие от времени данные между шагами UseCase'а, например если они хранятся в БД? Я такое в тестах часто использую, например при тестировании протухания ссылки активации пользователя на сайте.
Naota
Фев. 8, 2011 11:25:21
Пишу биллинг и использую datetime.now и в тестах time.sleep. Получается, в тестах надо написать свой sleep, который бы увеличивал время для datetime.now. Самое очевидное использовать свою библиотеку, где всё и править если идут тесты.
ziro
Фев. 8, 2011 12:21:55
Не уверен насчет библиотеки - достаточно простого модуля с применением условного импорта, например все запихиваем в модуль timeutils.py следующего содержания:
if config.TESTING:
# Эти функции у нас используются при тестировании
from datetime import datetime as _datetime, timedelta as _timedelta
current_time = None
def now():
"""
Mock для подмены стандартной функции datetime.now
"""
global current_time
if current_time is None:
current_time = _datetime.now()
return current_time
def sleep(seconds):
"""
Mock для подмены стандартной функции time.sleep
"""
global current_time
current_time += _timedelta(seconds=secons)
else:
# Это используется в реальной работе
from time import sleep
from datetime import datetime as _datetime
now = _datetime.now
Но чесно говоря не тестил.
PS: манкипатчинг не люблю.
Naota
Фев. 9, 2011 11:00:14
Мне нужно тестировать компоненты, которые внутри используют datetime.now
Андрей Светлов
Фев. 9, 2011 11:32:35
Еще один забавный трюк, который часто помогает.
import datetime
class A(object):
now = datetime.datetime.now
def __init__(self):
pass
def f(self):
return self.now() + datetime.timedelta(minutes=2)
#### Test
import unittest
import mocker
class TestA(unittest.TestCase):
def setUp(self):
self.mocker = mocker.Mocker()
def tearDown(self):
self.mocker = None
def test_something(self):
a = A()
now = self.mocker.mock()
a.now = now
current_time = datetime.datetime(2011, 2, 9, 11, 28, 33)
expected = datetime.datetime(2011, 2, 9, 11, 30, 33) # 2 mins later
now()
self.mocker.result(current_time)
with self.mocker:
ret = a.f()
self.assertEqual(expected, ret)
unittest.main()
Naota
Фев. 9, 2011 17:03:11
В тестах now нет, вот пример:
self.assertEqual(billing.can_show(), True)
time.sleep(4)
self.assertEqual(billing.can_show(), True)
time.sleep(4)
self.assertEqual(billing.can_show(), False)