python - 使用pytest的parametrize,如果一个测试用例失败,我如何跳过剩余的测试?

标签 python unit-testing pytest

我正在使用 pytest.mark.parametrize将越来越长的输入输入到一个相当慢的测试函数中,像这样:

@pytest.mark.parametrize('data', [
    b'ab',
    b'xyz'*1000,
    b'12345'*1024**2,
    ... # etc
])
def test_compression(data):
    ... # compress the data
    ... # decompress the data
    assert decompressed_data == data

因为压缩大量数据需要很长时间,所以我想在一个失败后跳过所有剩余的测试。例如,如果测试因输入 b'ab'(第一个)、b'xyz'*1000b'12345'*1024* 而失败*2 和所有其他参数化应被跳过(或 xfail 而不被执行)。

我知道可以像这样将标记附加到单个参数化:

@pytest.mark.parametrize("test_input,expected", [
    ("3+5", 8),
    ("2+4", 6),
    pytest.param("6*9", 42, marks=pytest.mark.xfail),
])

但我不知道如何根据先前测试用例的状态有条件地应用这些标记。有办法做到这一点吗?

最佳答案

标记在测试执行之前进行评估,因此无法传递某种依赖于其他测试结果的声明性标记(如 skipif)。不过,您可以在 Hook 中应用自定义测试跳过逻辑。修改 incremental testing - test steps pytest 文档中的配方:

# conftest.py
import pytest

def pytest_sessionstart(session):
    session.failednames = set()

def pytest_runtest_makereport(item, call):
    if call.excinfo is not None:
        item.session.failednames.add(item.originalname)

def pytest_runtest_setup(item):
    if item.originalname in item.session.failednames:
        pytest.skip("previous test failed (%s)" % item.name)  # or use pytest.xfail like in the other answer

示例测试

@pytest.mark.parametrize('i', range(10))
def test_spam(i):
    assert i != 3

产量:

=================================== test session starts ===================================
collected 10 items

test_spam.py::test_spam[0] PASSED
test_spam.py::test_spam[1] PASSED
test_spam.py::test_spam[2] PASSED
test_spam.py::test_spam[3] FAILED
test_spam.py::test_spam[4] SKIPPED
test_spam.py::test_spam[5] SKIPPED
test_spam.py::test_spam[6] SKIPPED
test_spam.py::test_spam[7] SKIPPED
test_spam.py::test_spam[8] SKIPPED
test_spam.py::test_spam[9] SKIPPED

========================================= FAILURES ========================================
_______________________________________ test_spam[3] ______________________________________

i = 3

    @pytest.mark.parametrize('i', range(10))
    def test_spam(i):
>       assert i != 3
E       assert 3 != 3

test_spam.py:5: AssertionError
====================== 1 failed, 3 passed, 6 skipped in 0.06 seconds ======================

编辑:使用自定义标记

def pytest_runtest_makereport(item, call):
    markers = {marker.name for marker in item.iter_markers()}
    if call.excinfo is not None and 'skiprest' in markers:
        item.session.failednames.add(item.originalname)

def pytest_runtest_setup(item):
    markers = {marker.name for marker in item.iter_markers()}
    if item.originalname in item.session.failednames and 'skiprest' in markers:
        pytest.skip(item.name)

用法:

@pytest.mark.skiprest
@pytest.mark.parametrize('somearg', ['a', 'b', 'c'])
def test_marked(somearg):
    ...

关于python - 使用pytest的parametrize,如果一个测试用例失败,我如何跳过剩余的测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52295214/

相关文章:

python - 为什么导入无法解决?

typescript - 使用注入(inject)对 NestJS Controller 进行单元测试

python - 测试 : Allow Failure Rate

python-3.x - 如何使用 pytestmonkeypatch 模拟两个连续的控制台输入

python - NDB 查询返回零结果。数据存储显示结果

python - 在Python中迭代数组时添加数组中的当前元素+数组中的下一个元素

Android Studio 运行单元测试显示 'Empty test suite'

java - JUnit - 用于测试单个类的文件有多少?

python - pytest:如何定义强制命令行参数

python - 我怎样才能将json文件制作成字典?