让我们假设我们有这样的感觉:
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。
答案 0 :(得分:73)
如果测试引发任何意外的异常,测试将失败。你可以调用foo(7),你将测试不会引发MyError。所以,以下就足够了:
def test_foo3():
foo(7)
如果你想明确并为此写一个断言语句,你可以这样做:
def test_foo3():
try:
foo(7)
except MyError:
pytest.fail("Unexpected MyError ..")
答案 1 :(得分:10)
建立在Oisin所提到的基础之上..
您可以创建一个与pytest not_raises
类似的简单raises
函数:
from contextlib import contextmanager
@contextmanager
def not_raises(exception):
try:
yield
except exception:
raise pytest.fail("DID RAISE {0}".format(exception))
如果你想坚持让raises
拥有对应物,那么你的测试更具可读性。从本质上讲,除了运行你想要在自己的行上测试的代码块之外,你真的不需要任何东西 - 一旦该块引发错误,pytest就会失败。
答案 2 :(得分:8)
自从这个问题得到回答后,pytest 文档已经更新了关于这个主题的信息,这里值得一提。
https://docs.pytest.org/en/6.2.x/example/parametrize.html#parametrizing-conditional-raising
它与其他一些答案类似,但使用 parametrize
和更新的内置 nullcontext
使解决方案非常干净。
一个潜在的 Python3.7+ 唯一示例如下所示:
from contextlib import nullcontext as does_not_raise
import pytest
@pytest.mark.parametrize(
"example_input,expectation",
[
(3, does_not_raise()),
(2, does_not_raise()),
(1, does_not_raise()),
(0, pytest.raises(ZeroDivisionError)),
],
)
def test_division(example_input, expectation):
"""Test how much I know division."""
with expectation:
assert (6 / example_input) is not None
答案 3 :(得分:6)
我很想知道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()
它确实有效。但是我不确定它是否真的很好读 测试