pytest标记:标记整个目录/包

时间:2019-07-14 21:49:30

标签: python testing pytest

我正在使用Pytest测试组件的多个版本。有些测试可以在所有版本上运行,有些测试是特定于版本的。例如

tests
|
|-- version1_tests
|   |-- test_feature_1_1.py
|   |-- test_feature_1_2.py
|   |-- test_feature_1_n.py
| 
|-- version2_tests
|   |-- test_feature_2_1.py
|   |-- test_feature_2_2.py
|   |-- test_feature_2_n.py
|
|-- common_tests
|   |-- test_feature_common_1.py
|   |-- test_feature_common_2.py
|   |-- test_feature_common_n.py

我想标记测试,以便可以从命令行选择是测试版本1(version1_tests + common_tests)还是版本2(version2_tests + common_tests)。

我当前对每个测试模块执行此操作的方式是,添加pytest标记,然后从命令行指定该标记。例如,在test_feature_1_1.py中:

import pytest
pytestmark = pytest.mark.version1

class TestSpecificFeature(object):
    ...

然后运行:python -m pytest -m "common and version1"

这很好用,但是我必须手动将标记添加到每个模块中,这很繁琐,因为实际上有几十个(而不是示例中的3个)。

我们曾经使用过Robot Framework,通过在__init__.robot文件中添加标签来“标记”整个文件夹很简单。在Pytest中是否有任何等效的方法可以做到这一点,或者每个模块都是我能做到的最好的标记?

3 个答案:

答案 0 :(得分:1)

您可以使用item.add_marker()方法在运行时注册标记以收集收集的测试。这是在pytest_collection_modifyitems中注册标记的示例:

import pathlib
import pytest


def pytest_collection_modifyitems(config, items):
    # python 3.4/3.5 compat: rootdir = pathlib.Path(str(config.rootdir))
    rootdir = pathlib.Path(config.rootdir)
    for item in items:
        rel_path = pathlib.Path(item.fspath).relative_to(rootdir)
        mark_name = next((part for part in rel_path.parts if part.endswith('_tests')), '').rstrip('_tests')
        if mark_name:
            mark = getattr(pytest.mark, mark_name)
            item.add_marker(mark)

将代码写入项目根目录中的conftest.py并进行尝试:

$ pytest -m "common or version2" --collect-only -q
tests/common_tests/test_feature_common_1.py::test_spam
tests/common_tests/test_feature_common_1.py::test_eggs
tests/common_tests/test_feature_common_2.py::test_spam
tests/common_tests/test_feature_common_2.py::test_eggs
tests/common_tests/test_feature_common_n.py::test_spam
tests/common_tests/test_feature_common_n.py::test_eggs
tests/version2_tests/test_feature_2_1.py::test_spam
tests/version2_tests/test_feature_2_1.py::test_eggs
tests/version2_tests/test_feature_2_2.py::test_spam
tests/version2_tests/test_feature_2_2.py::test_eggs
tests/version2_tests/test_feature_2_n.py::test_spam
tests/version2_tests/test_feature_2_n.py::test_eggs

仅选择了common_testsversion2_tests下的测试。

说明

对于每个收集的测试项目,我们提取相对于项目根目录(rel_path)的路径,以rel_path结尾的_tests的第一部分将用作标记的来源名称提取。例如。 collect_tests是商标名称collect等的来源。有了商标名称后,我们就创建了商标(使用getattr,因为我们不能使用属性访问权限)并附加通过item.add_marker(mark)进行标记。您可以编写自己的,不太抽象的版本,例如

for item in items:
    if `common_tests` in str(item.fspath):
        item.add_marker(pytest.mark.common)
    elif `version1_tests` in str(item.fspath):
        item.add_marker(pytest.mark.version1)
    elif `version2_tests` in str(item.fspath):
        item.add_marker(pytest.mark.version2)

注册标记

对于最新版本的pytest,由于未注册动态生成的标记,因此您应该收到PytestUnknownMarkWarning。请查看Registering markers部分中的解决方案-您可以在pytest.ini中添加标记名称:

[pytest]
markers =
    common
    version1
    version2

或通过pytest_configure钩子动态添加它们,例如

def pytest_configure(config):
    rootdir = pathlib.Path(config.rootdir)
    for dir_ in rootdir.rglob('*_tests'):
        mark_name = dir_.stem.rstrip('_tests')
        config.addinivalue_line('markers', mark_name)

答案 1 :(得分:0)

您可以在每个目录的 __init__.py 个文件中设置标记

import pytest

pytest.mark.version1

答案 2 :(得分:-1)

您可以将以下代码添加到要应用标记的目录中的conftest.py上:

def pytest_collection_modifyitems(items):
    for item in items:
        item.add_marker(pytest.mark.mymarker)

pytest_collection_modifyitems获取同一软件包内所有已收集测试的列表,因此此处是根据您的喜好调整测试的合适位置。参见pytest documentation on dynamically adding markers