pytest 如何在第一项断言失败后不退出 for 循环

Posted

技术标签:

【中文标题】pytest 如何在第一项断言失败后不退出 for 循环【英文标题】:pytest how not to exit the for loop after first item assert fails 【发布时间】:2022-01-05 23:48:06 【问题描述】:

我是 python 和 pytest 的新手。我正在尝试断言 2 个数据列表。由于列表中的第一个数据不匹配,因此断言在该点失败并且不继续进行下一项。但是我不希望我的执行停止,而是完成循环并捕获整体断言结果。有人可以帮我实现它吗?

代码

def test_compare_database():
        records_src = [(1,James,smith,123),(2,Granpa,smith,124),(3,Linda,smith,123)]
        records_trg = [(1,James,smith,111),(2,Granpa,ron,124),(3,Linda,smith,123)]
        for a, b in zip(records_src, records_trg):
            assert a == b

输出:列表比较中的第一项失败,这是正确的。但它止步于此。我希望整个 for 循环运行并捕获失败的结果。

============================= test session starts =============================
collecting ... collected 1 item

main_test.py::test_compare_database FAILED  
def test_compare_database():
            records_src = [(1,James,smith,123),(2,Granpa,smith,124),(3,Linda,smith,123)]
            records_trg = [(1,James,smith,111),(2,Granpa,ron,124),(3,Linda,smith,123)]
            for a, b in zip(records_src, records_trg):
>               assert a == b
E      AssertionError: assert (1,
 'James',
 'Smith',
 123,)
  != (1,
 'James',
 'Smith',
 111,)

【问题讨论】:

【参考方案1】:

在 python 中使用“try”和“except”关键字允许错误不会干扰程序。这是你要找的吗?如果您想要的话,您还可以将我使用的“out”变量更改为列表变量。我希望这会有所帮助:)

James:int=1
smith:int=2
Granpa:int=3
Linda:int=4
ron:int=5

def test_compare_database()->str:
    out:str=''
    records_src = [(1,James,smith,123),(2,Granpa,smith,124),(3,Linda,smith,123)]
    records_trg = [(1,James,smith,111),(2,Granpa,ron,124),(3,Linda,smith,123)]

    for a, b in zip(records_src,records_trg):
        try:
            assert a==b
            out+="success between "+str(a)+" and "+str(b)+'!'
        except AssertionError as ae:
            out+="there was an assertion error in the program between "+str(a)+" and "+str(b)+'!'
        out+='\n'

    return out

print(test_compare_database())

【讨论】:

【参考方案2】:

您可以使用参数化测试根据数据创建多个测试,因此每对元组将在不同的测试中单独断言

def data_source():
    records_src = [(1, 'James', 'smith', 123), (2, 'Granpa', 'smith', 124), (3, 'Linda', 'smith', 123)]
    records_trg = [(1, 'James', 'smith', 111), (2, 'Granpa', 'ron', 124), (3, 'Linda', 'smith', 123)]
    for a, b in zip(records_src, records_trg):
        yield a, b


@pytest.mark.parametrize('a, b', data_source())
def test_compare_database(a, b):
    assert a == b

控制台输出:

main_test.py::test_compare_database[a0-b0] FAILED                     [ 33%]
Tests\main_test.py:33 (test_compare_database[a0-b0])
(1, 'James', 'smith', 123) != (1, 'James', 'smith', 111)

Expected :(1, 'James', 'smith', 111)
Actual   :(1, 'James', 'smith', 123)
<Click to see difference>

a = (1, 'James', 'smith', 123), b = (1, 'James', 'smith', 111)

    @pytest.mark.parametrize('a, b', data_source())
    def test_compare_database(a, b):
>       assert a == b
E       AssertionError: assert (1, 'James', 'smith', 123) == (1, 'James', 'smith', 111)

main_test.py:36: AssertionError
FAILED                     [ 66%]
Tests\main_test.py:33 (test_compare_database[a1-b1])
(2, 'Granpa', 'smith', 124) != (2, 'Granpa', 'ron', 124)

Expected :(2, 'Granpa', 'ron', 124)
Actual   :(2, 'Granpa', 'smith', 124)
<Click to see difference>

a = (2, 'Granpa', 'smith', 124), b = (2, 'Granpa', 'ron', 124)

    @pytest.mark.parametrize('a, b', data_source())
    def test_compare_database(a, b):
>       assert a == b
E       AssertionError: assert (2, 'Granpa', 'smith', 124) == (2, 'Granpa', 'ron', 124)

main_test.py:36: AssertionError
PASSED                     [100%]

【讨论】:

谢谢你是个天才 嗨,这给了我循环中的所有结果。但是我看到了这样的错误“E _pytest.outcomes.XFailed: [NOTRUN] yield tests are removed in pytest 4.0 - test_compare_database will be忽略” @EverydayLearner 更新你的 pytest 版本。

以上是关于pytest 如何在第一项断言失败后不退出 for 循环的主要内容,如果未能解决你的问题,请参考以下文章

即使其中一些失败,如何运行所有 PyTest 断言?

pytest文档36-断言失败后还能继续执行pytest-assume

如何使用 python pytest 断言 2 个数据帧

在 Python 中测试另一个线程的结果时,当断言失败时,PyTest 测试套件是不是通过?

如何运行失败后不退出的命令,直到成功?

[接口测试_B] 04 Pytest断言处理_告警断言