Как использовать pytest, чтобы проверить, что ошибка НЕ поднята
Предположим, что мы имеем что-то вроде этого:
import py, pytest
ERROR1 = ' --- Error : value < 5! ---'
ERROR2 = ' --- Error : value > 10! ---'
class MyError(Exception):
def __init__(self, m):
self.m = m
def __str__(self):
return self.m
def foo(i):
if i < 5:
raise MyError(ERROR1)
elif i > 10:
raise MyError(ERROR2)
return i
# ---------------------- TESTS -------------------------
def test_foo1():
with pytest.raises(MyError) as e:
foo(3)
assert ERROR1 in str(e)
def test_foo2():
with pytest.raises(MyError) as e:
foo(11)
assert ERROR2 in str(e)
def test_foo3():
....
foo(7)
....
В: Как я могу сделать test_foo3() для проверки, что не вызвано MyError?
Очевидно, что я мог просто проверить:
def test_foo3():
assert foo(7) == 7
но я хочу проверить это через pytest.raises(). Возможно ли это?
Например: в случае, эта функция "foo" вообще не имеет возвращаемого значения,
def foo(i):
if i < 5:
raise MyError(ERROR1)
elif i > 10:
raise MyError(ERROR2)
это может иметь смысл протестировать этот путь, imho.
Ответы
Ответ 1
Тест будет терпеть неудачу, если он вызывает любое неожиданное исключение. Вы можете просто вызвать foo (7), и вы испытаете, что MyError не будет поднят. Итак, следующего достаточно:
def test_foo3():
foo(7)
Если вы действительно хотите написать инструкцию assert для этого, вы можете попробовать:
def test_foo3():
try:
foo(7)
except MyError:
pytest.fail("Unexpected MyError ..")
Ответ 2
Мне было любопытно узнать, будет ли работать not_raises. Быстрый тест этого
(Test_notraises.py):
from contextlib import contextmanager
@contextmanager
def not_raises(ExpectedException):
try:
yield
except ExpectedException, err:
raise AssertionError(
"Did raise exception {0} when it should not!".format(
repr(ExpectedException)
)
)
except Exception, err:
raise AssertionError(
"An unexpected exception {0} raised.".format(repr(err))
)
def good_func():
print "hello"
def bad_func():
raise ValueError("BOOM!")
def ugly_func():
raise IndexError("UNEXPECTED BOOM!")
def test_ok():
with not_raises(ValueError):
good_func()
def test_bad():
with not_raises(ValueError):
bad_func()
def test_ugly():
with not_raises(ValueError):
ugly_func()
Кажется, он работает. Однако я не уверен, действительно ли он хорошо читается в
тест.
Ответ 3
Основываясь на том, что упоминал Ойсин.
Вы можете сделать простую функцию not_raises
, которая действует аналогично pytest raises
:
from contextlib import contextmanager
@contextmanager
def not_raises(exception):
try:
yield
except exception:
raise pytest.fail("DID RAISE {0}".format(exception))
Это хорошо, если вы хотите придерживаться того, что raises
имеет аналог, и, следовательно, ваши тесты становятся более читабельными. В сущности, однако, вам действительно не нужно ничего, кроме просто запустить блок кода, который вы хотите протестировать на своей собственной линии - pytest все равно сбой, как только этот блок вызывает ошибку.