pytest 标记:标记整个目录/包 [英] Pytest marks: mark entire directory / package

查看:50
本文介绍了pytest 标记:标记整个目录/包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am testing several versions of a component using Pytest. Some tests can run on all versions, some are version specific. For example

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).

I would like to mark my tests such that I can select if I want to test Version 1 (version1_tests + common_tests) or Version 2 (version2_tests + common_tests) from the command line.

我目前这样做的方式是针对每个测试模块,我添加一个 pytest 标记,然后从命令行指定标记.例如,在 test_feature_1_1.py 中:

The way I am currently doing this is for each test module, I add a pytest marker and then specify the marker from the command line. For example, in test_feature_1_1.py:

import pytest
pytestmark = pytest.mark.version1

class TestSpecificFeature(object):
    ...

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

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

This works fine, but I have to manually add the marker to every module, which is tedious because there are actually dozens (not 3 like in the example).

我们曾经使用 Robot Framework,通过在 __init__.robot 文件中添加标签来标记"整个文件夹是微不足道的.在 Pytest 中是否有任何等效的方法可以做到这一点,或者是否将每个模块标记为我能做的最好的?

We used to use Robot Framework, where it was trivial to "mark" an entire folder by adding tags into the __init__.robot files. Is there any equivalent way to do this in Pytest, or is marking each module the best I can do?

推荐答案

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

You can register markers to collected tests at runtime using item.add_marker() method. Here's an example of registering markers in 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中试试:

Write the code to conftest.py in the project root dir and try it out:

$ 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 下的测试.

Only tests under common_tests and version2_tests were selected.

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

For each collected test item, we extract the path relative to project root dir (rel_path), first part of rel_path that ends with _tests will be used as source for the mark name extraction. E.g. collect_tests is the source for the mark name collect etc. Once we have the mark name, we create the mark (using getattr since we can't use the property access) and append the mark via item.add_marker(mark). You can write your own, less abstract version of it, e.g.

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,因为未注册动态生成的标记.查看注册标记部分以获得解决方案 -您可以在 pytest.ini 中添加标记名称:

Registering markers

With a recent version of pytest, you should receive a PytestUnknownMarkWarning since the dynamically generated markers were not registered. Check out the section Registering markers for a solution - you can either add the mark names in pytest.ini:

[pytest]
markers =
    common
    version1
    version2

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

or add them dynamically via pytest_configure hook, e.g.

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)

这篇关于pytest 标记:标记整个目录/包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆