如何在不修改代码的情况下禁用pytest中的测试?

时间:2019-05-10 13:20:26

标签: python unit-testing pytest python-decorators

我继承了一些实现pytest.mark.skipif的代码以进行一些测试。通过阅读pytest文档,我知道我可以添加条件,可能检查环境变量,或者使用pytest.mark的更高级功能一起控制测试组。不幸的是,到目前为止,文档中似乎没有任何东西可以解决我的问题。

我希望简单地关闭所有跳过测试的功能,但不修改测试的任何源代码。我只想在不接受任何测试跳过指标的模式下运行pytest。 pytest是否存在这样的解决方案?

4 个答案:

答案 0 :(得分:2)

使用以下内容创建conftest.py:

import pytest
import _pytest.skipping


def pytest_addoption(parser):
    parser.addoption(
        "--no-skips",
        action="store_true",
        default=False, help="disable skip marks")


@pytest.hookimpl(tryfirst=True)
def pytest_cmdline_preparse(config, args):
    if "--no-skips" not in args:
        return

    def no_skip(*args, **kwargs):
        return

    _pytest.skipping.skip = no_skip

即使在使用--no-skip装饰器的某些测试用例中,也可以在命令行中使用pytest.mark.skip运行所有测试用例

答案 1 :(得分:1)

好的,实现不允许对此进行零修改。您需要一个自定义标记。将以下内容添加到您的conftest.py中,然后将所有skipif标记更改为custom_skipif。使用pytest --no-skips

import pytest
from _pytest.mark.evaluate import MarkEvaluator

def pytest_addoption(parser):
    parser.addoption(
        "--no-skips", action="store_true", default=False, help="disable custom_skip marks"
    )

@hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
    if item.config.getoption('--no-skips'):
        return

    # Check if skip or skipif are specified as pytest marks
    item._skipped_by_mark = False
    eval_skipif = MarkEvaluator(item, "custom_skipif")
    if eval_skipif.istrue():
        item._skipped_by_mark = True
        pytest.skip(eval_skipif.getexplanation())

    for skip_info in item.iter_markers(name="custom_skip"):
        item._skipped_by_mark = True
        if "reason" in skip_info.kwargs:
            pytest.skip(skip_info.kwargs["reason"])
        elif skip_info.args:
            pytest.skip(skip_info.args[0])
        else:
            pytest.skip("unconditional skip")

    item._evalxfail = MarkEvaluator(item, "xfail")
    check_xfail_no_run(item)

该实现是从skiptest.py中的pytest本身复制和修改的。

答案 2 :(得分:1)

一种忽略跳过标记的解决方法是以编程方式删除它们。创建一个包含以下内容的conftest.py

def pytest_collection_modifyitems(items):
    for item in items:
        for node in reversed(item.listchain()):
            node.own_markers = [m for m in node.own_markers if m.name not in ('skip', 'skipif')]

但是,这与pytest的内部结构混淆,很容易在pytest更新时中断;忽略跳过的正确方法应该是定义您的自定义跳过机制,例如:

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_setup(item):
    mark = item.get_closest_marker(name='myskip')
    if mark:
        condition = next(iter(mark.args), True)
        reason = mark.kwargs.get('reason', 'custom skipping mechanism')
        item.add_marker(pytest.mark.skipif(not os.getenv('PYTEST_RUN_FORCE_SKIPS', False) and condition, reason=reason), append=False)

@pytest.mark.myskip而不是@pytest.mark.skip@pytest.mark.myskip(condition, reason)而不是@pytest.mark.skipif(condition, reason)注释测试:

@pytest.mark.myskip
def test_skip():
    assert True


@pytest.mark.myskip(1 == 1, reason='my skip')
def test_skipif():
    assert True

在常规运行中,myskip的行为与pytest.mark.skip / pytest.mark.skipif相同。设置PYTEST_RUN_FORCE_SKIPS将禁用它:

$ PYTEST_RUN_FORCE_SKIPS=1 pytest -v
...
test_spam.py::test_skip PASSED
test_spam.py::test_skipif PASSED
...

当然,您不应该再使用pytest.mark.skip / pytest.mark.skipif,因为它们不会受到PYTEST_RUN_FORCE_SKIPS环境变量的影响。

答案 3 :(得分:1)

一个简单的解决方法是在您的pytest.mark.skipif中修补conftest.py

import pytest

old_skipif = pytest.mark.skipif

def custom_skipif(*args, **kwargs):
    return old_skipif(False, reason='disabling skipif')

pytest.mark.skipif = custom_skipif