我如何正确地断言 pytest 中引发了异常?

2025-02-14 09:49:00
admin
原创
72
摘要:问题描述:代码:# coding=utf-8 import pytest def whatever(): return 9/0 def test_whatever(): try: whatever() except ZeroDivisionError as exc...

问题描述:

代码:

# coding=utf-8
import pytest


def whatever():
    return 9/0

def test_whatever():
    try:
        whatever()
    except ZeroDivisionError as exc:
        pytest.fail(exc, pytrace=True)

输出:

================================ test session starts =================================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
plugins: django, cov
collected 1 items 

pytest_test.py F

====================================== FAILURES ======================================
___________________________________ test_whatever ____________________________________

    def test_whatever():
        try:
            whatever()
        except ZeroDivisionError as exc:
>           pytest.fail(exc, pytrace=True)
E           Failed: integer division or modulo by zero

pytest_test.py:12: Failed
============================== 1 failed in 1.16 seconds ==============================

我如何让 pytest 打印回溯,以便看到函数中whatever引发异常的位置?


解决方案 1:

pytest.raises(Exception)就是您所需要的。

代码

import pytest

def test_passes():
    with pytest.raises(Exception) as e_info:
        x = 1 / 0

def test_passes_without_info():
    with pytest.raises(Exception):
        x = 1 / 0

def test_fails():
    with pytest.raises(Exception) as e_info:
        x = 1 / 1

def test_fails_without_info():
    with pytest.raises(Exception):
        x = 1 / 1

# Don't do this. Assertions are caught as exceptions.
def test_passes_but_should_not():
    try:
        x = 1 / 1
        assert False
    except Exception:
        assert True

# Even if the appropriate exception is caught, it is bad style,
# because the test result is less informative
# than it would be with pytest.raises(e)
# (it just says pass or fail.)

def test_passes_but_bad_style():
    try:
        x = 1 / 0
        assert False
    except ZeroDivisionError:
        assert True

def test_fails_but_bad_style():
    try:
        x = 1 / 1
        assert False
    except ZeroDivisionError:
        assert True

输出

============================================================================================= test session starts ==============================================================================================
platform linux2 -- Python 2.7.6 -- py-1.4.26 -- pytest-2.6.4
collected 7 items 

test.py ..FF..F

=================================================================================================== FAILURES ===================================================================================================
__________________________________________________________________________________________________ test_fails __________________________________________________________________________________________________

    def test_fails():
        with pytest.raises(Exception) as e_info:
>           x = 1 / 1
E           Failed: DID NOT RAISE

test.py:13: Failed
___________________________________________________________________________________________ test_fails_without_info ____________________________________________________________________________________________

    def test_fails_without_info():
        with pytest.raises(Exception):
>           x = 1 / 1
E           Failed: DID NOT RAISE

test.py:17: Failed
___________________________________________________________________________________________ test_fails_but_bad_style ___________________________________________________________________________________________

    def test_fails_but_bad_style():
        try:
            x = 1 / 1
>           assert False
E           assert False

test.py:43: AssertionError
====================================================================================== 3 failed, 4 passed in 0.02 seconds ======================================================================================

请注意,e_info保存异常对象以便您可以从中提取详细信息。例如,如果您想检查异常调用堆栈或其中的另一个嵌套异常。

解决方案 2:

你的意思是这样的吗:

def test_raises():
    with pytest.raises(Exception) as exc_info:   
        raise Exception('some info')
    # these asserts are identical; you can use either one   
    assert exc_info.value.args[0] == 'some info'
    assert str(exc_info.value) == 'some info'

解决方案 3:

Pytest 不断发展!可以同时测试

  • 异常类型(严格测试)

  • 错误消息(使用正则表达式进行严格或宽松检查)

文档中的两个示例:

with pytest.raises(ValueError, match='must be 0 or None'):
    raise ValueError('value must be 0 or None')
with pytest.raises(ValueError, match=r'must be d+$'):
    raise ValueError('value must be 42')

我已经在许多项目中使用了这种方法,并且非常喜欢它。

注意:
ilya-rusin的评论也建议了上述方法。

解决方案 4:

在 pytest 中有两种方法可以处理此类情况:

  • 使用pytest.raises函数

  • 使用pytest.mark.xfail装饰器

正如文档所述:

对于测试您自己的代码故意引发的异常的情况,使用pytest.raises可能更好,而@pytest.mark.xfail对于记录未修复的错误(测试描述“应该”发生什么)或依赖项中的错误等情况,使用检查函数可能更好。

用法pytest.raises

def whatever():
    return 9/0
def test_whatever():
    with pytest.raises(ZeroDivisionError):
        whatever()

用法pytest.mark.xfail

@pytest.mark.xfail(raises=ZeroDivisionError)
def test_whatever():
    whatever()

输出pytest.raises

============================= test session starts ============================
platform linux2 -- Python 2.7.10, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- 
/usr/local/python_2.7_10/bin/python
cachedir: .cache
rootdir: /home/user, inifile:
collected 1 item

test_fun.py::test_whatever PASSED


======================== 1 passed in 0.01 seconds =============================

标记输出pytest.xfail

============================= test session starts ============================
platform linux2 -- Python 2.7.10, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- 
/usr/local/python_2.7_10/bin/python
cachedir: .cache
rootdir: /home/user, inifile:
collected 1 item

test_fun.py::test_whatever xfail

======================== 1 xfailed in 0.03 seconds=============================

解决方案 5:

你可以尝试

def test_exception():
    with pytest.raises(Exception) as excinfo:   
        function_that_raises_exception()   
    assert str(excinfo.value) == 'some info' 

解决方案 6:

有两种方法可以处理异常pytest

  1. 用于pytest.raises编写有关引发的异常的断言

  2. 使用@pytest.mark.xfail

1. 使用pytest.raises

来自文档:

为了编写有关引发异常的断言,你可以使用pytest.raises上下文管理器

例子:

断言只是一个例外:

import pytest


def test_zero_division():
    with pytest.raises(ZeroDivisionError):
        1 / 0

with pytest.raises(ZeroDivisionError)表示下一个代码块中的任何内容都应引发ZeroDivisionError异常。如果没有引发异常,则测试失败。如果测试引发了不同的异常,则测试失败。

如果您需要访问实际的异常信息:

import pytest

def f():
    f()

def test_recursion_depth():
    with pytest.raises(RuntimeError) as excinfo:
        f()
    assert "maximum recursion" in str(excinfo.value)

excinfo是一个实例,它是实际引发的异常的ExceptionInfo包装器。主要感兴趣的属性是.type和。.value`.traceback`

2. 使用@pytest.mark.xfail

也可以为指定一个raises参数pytest.mark.xfail

import pytest

@pytest.mark.xfail(raises=IndexError)
def test_f():
    l = [1, 2, 3]
    l[10]

@pytest.mark.xfail(raises=IndexError)表示下一个代码块中的任何内容都应引发IndexError异常。如果IndexError引发异常,则测试被标记为xfailed (x)。如果没有引发异常,则测试被标记为xpassed (X)。如果测试引发不同的异常,则测试失败。

笔记:

  • 对于测试您自己的代码故意引发的异常的情况,使用pytest.raises可能更好,而@pytest.mark.xfail对于记录未修复的错误或依赖项中的错误等情况,使用检查函数可能更好。

  • 您可以将match关键字参数传递给上下文管理器(pytest.raises)来测试正则表达式是否与异常的字符串表示匹配。(查看更多)

解决方案 7:

正确的方法是使用,但我在这里的pytest.raises评论中发现了有趣的替代方法,并希望将其保存以供将来阅读该问题的读者使用:

try:
    thing_that_rasises_typeerror()
    assert False
except TypeError:
    assert True

解决方案 8:

我们正在使用的解决方案是:

def test_date_invalidformat():
    """
    Test if input incorrect data will raises ValueError exception
    """
    date = "06/21/2018 00:00:00"
    with pytest.raises(ValueError):
        app.func(date) #my function to be tested

请参考 pytest,https://docs.pytest.org/en/latest/reference.html#pytest-raises

解决方案 9:

如果要测试特定的错误类型,请结合使用 try、catch 和 raise:

#-- test for TypeError
try:
  myList.append_number("a")
  assert False
except TypeError: pass
except: assert False

解决方案 10:

只是添加另一个“愚蠢”的建议,因为我在现有答案中没有看到它。本质上,您可以将错误变量初始化为None,在 try/except 块中执行操作,然后检查错误变量的类/值

e = None

try:
    blah()
except Exception as exc:
    e = exc

assert e.__class__ == ValueError # or whatever you expect
assert str(e) == "expected message"

解决方案 11:

如果您预计测试用例会引发异常,那么此处提交的最佳答案将非常有用。如果您的测试可能会引发异常,并且您希望在两种情况下都能妥善处理它,那么它就没什么用了。

如果您有一个可能(不会)引发异常的测试用例,我认为这可能是一个更好的选择。

@python.mark.parametrize("request_query, response_code", query_response_dataset)
def test_big_query_submission(request_query, response_code):
    try:
        stats = bigquery.Client().query(request_query)
    except Exception as e:
        assert False, f"Exception raised: {e}"
    assert stats.errors is None

这样,您就可以优雅地失败测试,​​而不是因为任何原因引发异常而导致测试崩溃。

解决方案 12:

您是否尝试过删除“pytrace=True”?

pytest.fail(exc, pytrace=True) # before
pytest.fail(exc) # after

您是否尝试过使用“--fulltrace”运行?

解决方案 13:

更好的做法是使用继承 unittest.TestCase 的类并运行 self.assertRaises。

例如:

import unittest


def whatever():
    return 9/0


class TestWhatEver(unittest.TestCase):

    def test_whatever():
        with self.assertRaises(ZeroDivisionError):
            whatever()

然后你可以通过运行来执行它:

pytest -vs test_path

解决方案 14:

我刚写了一个钩子,每个测试都会得到

钩子:

@pytest.hookimpl(tryfirst = True,hookwrapper = True)def pytest_runtest_makereport(item:Item,call:CallInfo):

    outcome = yield  # The result after the test is completed
    result = outcome.get_result()

    if result.when == "call":
       if result.failed == True:

       else:

我有一个函数,可以使用测试结果更新文档并使用以下方法添加跟踪:result.longrepr.reprcrash.message

我不知道这是否是最好的方法,但它确实回答了如何仅使用 pytest 打印回溯的问题

@Obviously我还有一些其他代码

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   3970  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   2740  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Freshdesk、ClickUp、nTask、Hubstaff、Plutio、Productive、Targa、Bonsai、Wrike。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在项目管理过程中面临着诸多痛点,如任务分配不...
项目管理系统   79  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Monday、TeamGantt、Filestage、Chanty、Visor、Smartsheet、Productive、Quire、Planview。在当今快速变化的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多项目经理和团队在管理复杂项目时,常...
开源项目管理工具   87  
  本文介绍了以下10款项目管理软件工具:禅道项目管理软件、Smartsheet、GanttPRO、Backlog、Visor、ResourceGuru、Productive、Xebrio、Hive、Quire。在当今快节奏的商业环境中,项目管理已成为企业成功的关键因素之一。然而,许多企业在选择项目管理工具时常常面临困惑:...
项目管理系统   74  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用