如何使用 pytest 来检查错误是否被引发

让我们假设我们有这样的 smth:

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.rose ()测试一下,有可能吗? 例如: 在一个例子中,那个函数“ foo”根本没有返回值,

def foo(i):
if i < 5:
raise MyError(ERROR1)
elif i > 10:
raise MyError(ERROR2)

用这种方法测试是有意义的,我的天。

94648 次浏览

如果测试引发任何类型的意外异常,则测试将失败。您只需调用 foo (7) ,就可以测试没有引发 MyError。因此,以下内容就足够了:

def test_foo3():
foo(7)

如果您希望显式地为此编写断言语句,可以这样做:

def test_foo3():
try:
foo(7)
except MyError:
pytest.fail("Unexpected MyError ..")

我很好奇不加薪是否有效 (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()

它看起来确实有效。但是我不确定它是否真的在 测试。

根据 Oisin 提到的。

你可以创建一个简单的 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 就会失败。

自从这个问题得到了回答,pytest 文档已经更新了关于这个主题的信息,这里值得一提。

Https://docs.pytest.org/en/6.2.x/example/parametrize.html#parametrizing-conditional-raising

它类似于其他一些答案,但使用 parametrize和更新的内置 nullcontext,使解决方案真正干净。

一个可能的 Python 3.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

以这种方式使用 parametrize使得组合 OP 的测试用例成为可能,比如:

@pytest.mark.parametrize(
"example_input,expectation,message",
[
(3, pytest.raises(MyError), ERROR1),
(11, pytest.raises(MyError), ERROR2),
(7, does_not_raise(), None),
],
)
def test_foo(example_input, expectation, message):
with expectation as e:
foo(example_input)
assert message is None or message in str(e)

这样做允许您测试它 没有提出 < strong > 任何 例外nullcontext意味着作为可选上下文管理器(在本例中为 pytest.raises)的替身。它实际上没有做任何事情,所以如果你想测试它 没有引发 < strong > 具体 异常,你应该看到其他答案之一。