Python 如何使用pytest检查未引发错误

Python 如何使用pytest检查未引发错误,python,pytest,raise,Python,Pytest,Raise,假设我们有这样的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):

假设我们有这样的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)
         ....
但是我想通过pytest.raises()来测试这一点。有可能吗? 例如:在一个例子中,函数“foo”根本没有返回值

def foo(i):
    if i < 5:
        raise MyError(ERROR1)
    elif i > 10:
        raise MyError(ERROR2)
def foo(i):
如果i<5:
升起我的错误(错误1)
如果i>10:
升起我的错误(错误2)

以这种方式进行测试是有意义的,imho。

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

def test_foo3():
    foo(7)
如果希望显式并为此编写assert语句,可以执行以下操作:

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

我很好奇,想看看不加薪是否管用。这方面的一个快速测试是 (test_notraises.py):

它似乎确实起作用了。然而,我不确定它是否真的在报纸上读得好
测试。

在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))

如果您希望坚持使用
提升
副本,从而使测试更具可读性,那么这是很好的。但本质上,除了在自己的代码行上运行要测试的代码块之外,您并不需要任何东西——只要该代码块出现错误,pytest就会失败。

由于这个问题得到了回答,pytest文档已经更新了关于这个主题的信息,值得在此提及

它与其他一些答案类似,但使用
参数化
和更新的内置
nullcontext
,使解决方案真正干净

潜在的Python3.7+示例如下所示:

从contextlib导入nullcontext as不引发
导入pytest
@pytest.mark.parametize(
“示例输入,期望值”,
[
(3,不升起()),
(2,不升起()),
(1,不升起()),
(0,pytest.raises(ZeroDivisionError)),
],
)
def测试部门(示例输入、预期):
“测试我对除法的了解程度。”
期望:
断言(6/示例_输入)不是无

谢谢,它是有效的,但它似乎更像是一种黑客行为,而不是一种干净的解决方案。例如,对foo(4)的测试将失败,但不是由于断言错误。对foo(4)的测试将失败,因为它将抛出一个不期望的异常。另一种方法是将其包装在try-catch块中,并使用特定消息失败。我会更新我的答案。如果你有很多这样的情况,在一个简单的函数中写下它可能会很有用:``def not_raises(error_class,func,*args,**kwargs):```````或者您也可以像pytest那样使用类似的方法编写一个测试。如果你这样做,我建议你写一份公关,让所有人受益。:)(存储库在中)。@paraklet-pytest的主要口号是。在pytest为您处理细节时,您可以像Faruk的第一个示例中那样编写测试,这非常符合pytest的精神。对我来说,第一个例子是“干净的解决方案”,第二个看起来不必要的冗长。我喜欢代码可读。如果我看到
pytest.notRaises()
我清楚地看到测试的目的是检查是否没有抛出异常。如果我只是执行代码,没有任何断言,我的第一个想法是“这里缺少了一些东西…”。是的,我可以为此写评论,但我更喜欢代码是自解释的,而不是注释。它看起来像是在搜索问题,代码测试
foo(7)
很好。您将获得正确的消息,并且使用所有pytest输出进行调试将更容易。您从@Faruk(
'Unexpected error…“
)强制执行的建议与错误无关,您将被卡住。你能做的唯一一件事就是更好地表达你的意图,比如
test\u foo3\u对\u range()内的\u integers\u工作。
。相关:我希望这是py.test中内置的;在某些情况下,它会使测试更具可读性。特别是与
@pytest.mark.parametize一起使用时。我非常欣赏这种方法的代码可读性!为python3更新了我希望接受的答案能尽快用这个更新
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()
from contextlib import contextmanager

@contextmanager
def not_raises(exception):
  try:
    yield
  except exception:
    raise pytest.fail("DID RAISE {0}".format(exception))