Переопределить функцию python-local в unittest
У меня есть метод в python (2.7), который делает foo и сбрасывается через 5 минут, если foo не работает.
def keep_trying(self):
timeout = 300 #empirically derived, appropriate timeout
end_time = time.time() + timeout
while (time.time() < end_time):
result = self.foo()
if (result == 'success'):
break
time.sleep(2)
else:
raise MyException('useful msg here')
Я знаю некоторые возможные результаты от foo(), поэтому я использую mock для подделки этих возвращаемых значений. Проблема в том, что я не хочу, чтобы тест выполнялся за 5 минут до того, как он увидит исключение.
Есть ли способ переопределить это локальное значение таймаута? Я бы хотел, чтобы это было всего несколько секунд, так что я вижу, что цикл пытается пару раз, а затем сдаваться и подниматься.
Не работает следующее:
@patch.object(myClass.keep_trying, 'timeout')
@patch.object(myClass, 'foo')
def test_keep_trying(self, mock_foo, mock_timeout):
mock_foo.return_value = 'failed'
mock_timeout.return_value = 10 # raises AttributeError
mock_timeout = 10 # raises AttributeError
...
Ответы
Ответ 1
Вместо того, чтобы пытаться высмеять значение, если timeout
, вы захотите высмеять возвращаемое значение time.time()
.
например.
@patch.object(time, 'time')
def test_keep_trying(self, mock_time):
mock_time.side_effect = iter([100, 200, 300, 400, 500, 600, 700, 800])
...
Теперь, когда вызывается первый раз time.time()
, вы получите значение 100, поэтому он должен истечь, если после нескольких оборотов вашего цикла while. Вы также можете высмеять time.sleep
и просто подсчитать, сколько раз оно вызывается, чтобы убедиться, что часть кода работает правильно.
Другой подход (который не является полностью ортогональным выше) заключается в том, чтобы позволить пользователю передать необязательное ключевое слово timeout для функции:
def keep_trying(self, timeout=300):
...
Это позволяет вам указать любой тайм-аут, который вы хотите в тестах (и в будущем коде, который не хочет ждать 5 минут; -).
Ответ 2
Вы не можете издеваться над локальной переменной функции. Чтобы ваш код был легче протестирован, измените его на, например:
def keep_trying(self, timeout=300):
end_time = time.time() + timeout
# etc, as above
поэтому для тестов запускать его с меньшим таймаутом становится тривиальным!