Я хочу написать hypothesis.stateful.RuleBasedStateMachine
, который утверждает, что исключение возникает при определенных обстоятельствах. pytest
предоставляет менеджер контекста raises
для написания тестов об исключениях. Если я использую pytest.raises
внутри hypothesis.stateful.rule
, последовательность шагов, приводящих к неудаче теста, не сообщается , а не .
Перезапись правила без pytest.raises
приводит к желаемому поведению: отображается последовательность шагов.
Вот пример кода:
from os import getenv
from pytest import raises
from hypothesis.stateful import RuleBasedStateMachine, rule
SHOW_PROBLEM = getenv('SHOW_PROBLEM') == 'yes'
# A state machine which asserts that an exception is raised in under some condition
class FifthCallShouldRaiseValueError(RuleBasedStateMachine):
def __init__(self):
super().__init__()
self.model = Model()
self.count = 0
if SHOW_PROBLEM:
# This version does NOT report the rule sequence
@rule()
def the_rule(self):
self.count += 1
if self.count > 4:
with raises(ValueError):
self.model.method()
else:
# This version DOES report the rule sequence
@rule()
def the_rule(self):
self.count += 1
if self.count > 4:
try:
self.model.method()
except ValueError: assert True
except : assert False
else : assert False
T = FifthCallShouldRaiseValueError.TestCase
# A model that deliberately fails the test, triggering reporting of
# the sequence of steps which lead to the failure.
class Model:
def __init__(self):
self._count = 0
def method(self):
self._count += 1
if self._count > 4:
# Deliberate mistake: raise wrong exception type
raise TypeError
Чтобы увидеть разницу в поведении, выполните тест с помощью
SHOW_PROBLEM=yes pytest <...>
SHOW_PROBLEM=no pytest <...>
Во втором случае вывод будет показывать
state = FifthCallShouldRaiseValueError()
state.the_rule()
state.the_rule()
state.the_rule()
state.the_rule()
state.the_rule()
state.teardown()
Эта последовательность шагов отсутствует в выходных данных в первом случае. Это желательно: последовательность должна быть показана в обоих случаях.
pytest.raises
повышает Failed: DID NOT RAISE <class 'ValueError'>
, в то время как рукописная версия повышает AssertionError
. Первый более информативен, когда речь идет о невозможности вызвать требуемое исключение, но каким-то образом препятствует hypothesis.stateful
сообщать о последовательности шагов, что говорит нам о том, как мы попали в это состояние, и часто является наиболее интересной частью выход.
Что можно сделать, чтобы смягчить это, то есть, чтобы распечатать последовательность шагов, кроме того, чтобы не использовать pytest.raises
?