我正在使用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中是否有任何等效的方法可以做到这一点,或者每个模块都是我能做到的最好的标记?
答案 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_tests
和version2_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。