Следующая проблема может быть связана с тем, что код не запускается несколько раз и / или не позволяет вам удалять / создавать таблицы.Независимо от того, решит ли это вашу проблему, это то, о чем вы, возможно, не знаете, и очень важно помнить.:)
Когда вы запускаете свои тесты несколько раз, db.drop_all()
может не вызываться (потому что один из ваших тестов не прошел) и, следовательно, он не сможет создать таблицы при следующем запуске (так какони уже существуют).Проблема заключается в использовании контекстного менеджера без try: finally:
.(ПРИМЕЧАНИЕ. Каждый прибор, использующий yield
, является контекстным менеджером).
from contextlib import contextmanager
def test_foo(db):
print('begin foo')
raise RuntimeError()
print('end foo')
@contextmanager
def get_db():
print('before')
yield 'DB object'
print('after')
Этот код представляет ваш код, но без использования функциональности pytest.Pytest запускает его более или менее как
try:
with get_db(app) as db:
test_foo(db)
except Exception as e:
print('Test failed')
Можно ожидать, что результат будет похож на:
before
begin_foo
after
Test failed
, но мы получим только
before
begin_foo
Test failed
Пока контекстный менеджерактивен (yield
был выполнен), наш тестовый метод запущен.Если во время выполнения нашей тестовой функции возникает исключение, выполнение останавливается БЕЗ выполнения какого-либо кода после оператора yield
.Чтобы предотвратить это, мы должны обернуть наш fixture
/ contextmanager
в блок try: ... finally:
.Поскольку finally выполняется ВСЕГДА независимо от того, что произошло.
@contextmanager
def get_db():
print('before')
try:
yield 'DB object'
finally:
print('after')
Код после оператора yield
теперь выполняется должным образом.
before
begin foo
after
Test failed
Есливы хотите узнать больше, см. соответствующий раздел в contextmanager docs :
В момент, когда генератор сдается, выполняется блок, вложенный в оператор with.Затем генератор возобновляется после выхода из блока.Если в блоке возникает необработанное исключение, оно повторно вызывается внутри генератора в точке, где произошел выход.Таким образом, вы можете использовать оператор try… кроме… finally, чтобы перехватить ошибку (если она есть) или убедиться, что какая-то очистка произошла.