Следующий код воспроизводит мою ситуацию:
from nose.tools import timed
from time import sleep
class Test():
@timed(1)
def test_slow_function(self):
duration = 5
sleep(duration)
pass
Запуск теста (например, nosetests test.py:Test -s
), я ожидал бы результат отказа всего через 1 секунду. К моему удивлению, это не сработает, пока тест не завершится (в этом случае через 5 секунд). Даже если какой-либо результат через 1 секунду будет неудачным. Я получил:
...
raise TimeExpired("Time limit (%s) exceeded" % limit)
nose.tools.nontrivial.TimeExpired: Time limit (1) exceeded
----------------------------------------------------------------------
Ran 1 test in 5.006s
FAILED (failures=1)
Я хочу избежать возможности того, что набор тестов никогда не заканчивается (например, при определенных обстоятельствах существует бесконечный цикл). Что было бы хорошим подходом?
@timed
декоратор не может остановить выполнение украшенной функции. Все, что он делает, просто сравнивает реальное время выполнения с ожидаемым, и повышает уровень сбоев, если он превышен.
В основном, чтобы контролировать какой-то процесс и останавливать его в каком-то случае (если он слишком длинный, в вашем примере), вам нужен другой процесс параллельно, который фактически выполняет мониторинг. Легкий и немного хакерский способ, которым вы можете достичь этого, заключается в использовании параллельного тестирования на nose
, например:
$ nosetests test.py:Test -s --processes 2 --process-timeout 1
E
======================================================================
ERROR: timesout_nose.Test.test_slow_function
----------------------------------------------------------------------
Traceback (most recent call last):
File "/test.py", line 9, in test_slow_function
sleep(duration)
File "/venv/lib/python3.6/site-packages/nose/plugins/multiprocess.py", line 276, in signalhandler
raise TimedOutException()
nose.plugins.multiprocess.TimedOutException: 'test.Test.test_slow_function'
----------------------------------------------------------------------
Ran 1 test in 1.230s
FAILED (errors=1)
Вы можете прочитать здесь: http://nose.readthedocs.io/en/latest/plugins/multiprocess.html
Однако вы не сможете настроить простой лимит времени, как это было с декоратором. Но вы все равно можете поймать бесконечные циклы.