pytest是否支持"默认"标记?

JS.*_*JS. 7 python pytest

我正在使用pytest来测试嵌入式系统的python模型.要测试的功能因平台而异.(我在这个上下文中使用'platform'来表示嵌入式系统类型,而不是OS类型).

组织我的测试最直接的方法是根据平台类型将它们分配给目录.

/platform1
/platform2
/etc.
Run Code Online (Sandbox Code Playgroud)

pytest/platform1

由于许多功能在不同平台上重叠,因此很快就难以支持.我已经将我的测试移动到一个目录中,每个功能区域的测试分配给一个文件名(例如test_functionalityA.py).然后我使用pytest标记来指示文件中的哪些测试适用于给定平台.

@pytest.mark.all_platforms
def test_some_functionalityA1():
    ...

@pytest.mark.platform1
@pytest.mark.platform2
def test_some_functionlityA2():
    ...
Run Code Online (Sandbox Code Playgroud)

虽然我喜欢得到"conftest"自动检测平台类型,仅运行相应的测试,我已经辞职自己指定它测试在命令行上运行.

pytest -m"(platform1或all_platforms)"

问题:(终于!)

有没有办法简化事情并让pytest默认运行所有未标记的测试,另外所有测试都通过命令行上的'-m'传递?

例如:pytest -m"platform1"

会运行标记@ pytest.mark.platform1的测试以及所有标记为@ pytest.mark.all_platforms的测试,甚至所有测试都没有@ pytest.mark吗?

鉴于大量共享功能,能够删除@ pytest.mark.all_platforms行将是一个很大的帮助.

hpk*_*k42 9

让我们解决完整的问题.我认为你可以把一个conftest.py文件和你的测试放在一起,它会注意跳过所有不匹配的测试(非标记的测试总是匹配,因此永远不会被跳过).这里我使用的是sys.platform,但我相信你有不同的方法来计算你的平台价值.

# content of conftest.py
#
import sys
import pytest

ALL = set("osx linux2 win32".split())

def pytest_runtest_setup(item):
    if isinstance(item, item.Function):
        plat = sys.platform
        if not hasattr(item.obj, plat):
            if ALL.intersection(set(item.obj.__dict__)):
                pytest.skip("cannot run on platform %s" %(plat))
Run Code Online (Sandbox Code Playgroud)

有了它,你可以像这样标记你的测试::

# content of test_plat.py

import pytest

@pytest.mark.osx
def test_if_apple_is_evil():
    pass

@pytest.mark.linux2
def test_if_linux_works():
    pass

@pytest.mark.win32
def test_if_win32_crashes():
    pass

def test_runs_everywhere_yay():
    pass
Run Code Online (Sandbox Code Playgroud)

如果你运行::

$ py.test -rs
Run Code Online (Sandbox Code Playgroud)

然后你可以运行它,并会看到至少两个测试被跳过,并且总是至少执行一次测试::

然后你会看到两个测试跳过和两个执行测试按预期::

$ py.test -rs # this option reports skip reasons
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.2.5.dev1
collecting ... collected 4 items

test_plat.py s.s.
========================= short test summary info ==========================
SKIP [2] /home/hpk/tmp/doc-exec-222/conftest.py:12: cannot run on platform linux2

=================== 2 passed, 2 skipped in 0.01 seconds ====================
Run Code Online (Sandbox Code Playgroud)

请注意,如果您通过marker-command line选项指定平台,例如::

$ py.test -m linux2
=========================== test session starts ============================
platform linux2 -- Python 2.7.3 -- pytest-2.2.5.dev1
collecting ... collected 4 items

test_plat.py .

=================== 3 tests deselected by "-m 'linux2'" ====================
================== 1 passed, 3 deselected in 0.01 seconds ==================
Run Code Online (Sandbox Code Playgroud)

那么未标记的测试将不会运行.因此,这是一种将运行限制为特定测试的方法.


Nat*_*Nat 6

迟到了,但我刚刚通过向所有未标记的测试添加默认标记解决了类似的问题。

作为问题的直接答案:您可以始终运行未标记的测试,并仅包含通过-m选项指定的标记测试,方法是将以下内容添加到 conftest.py

def pytest_collection_modifyitems(items, config):
    # add `always_run` marker to all unmarked items
    for item in items:
        if not any(item.iter_markers()):
            item.add_marker("always_run")
    # Ensure the `always_run` marker is always selected for
    markexpr = config.getoption("markexpr", 'False')
    config.option.markexpr = f"always_run or ({markexpr})"
Run Code Online (Sandbox Code Playgroud)