摘要:
我正在尝试使用
pytest_addoption
功能设置自定义 pytest 选项。
但是当在使用所述自定义选项时尝试使用
project.toml
文件配置我的项目时,我得到出现以下错误:
$ pytest --foo foo
ERROR: usage: pytest [options] [file_or_dir] [file_or_dir] [...]
pytest: error: unrecognized arguments: --foo
inifile: /home/vmonteco/Code/MREs/pytest__addoption__pyproject_toml/01_adding_pyproject.toml/pyproject.toml
rootdir: /home/vmonteco/Code/MREs/pytest__addoption__pyproject_toml/01_adding_pyproject.toml
尽管配置了测试路径,为什么还是出现此问题?我该如何解决它?
使用的版本是:
- Python 3.10.13
- Pytest 8.1.1
如何重现:
第 1 步 - 在组织项目之前,它可以工作:
我在单个目录中从一个非常简单的测试开始。
$ tree
.
├── conftest.py
└── test_foo.py
1 directory, 2 files
$
-
conftest.py
:
import pytest
def pytest_addoption(parser):
parser.addoption("--foo", action="store")
@pytest.fixture
def my_val(request):
return request.config.getoption("--foo")
-
test_foo.py
:
def test_foo(my_val):
assert my_val == "foo"
$ pytest --foo bar
=============================== test session starts ===============================
platform linux -- Python 3.10.13, pytest-8.1.1, pluggy-1.5.0
rootdir: /home/vmonteco/code/MREs/pytest__addoption__pyproject_toml/00_simplest_case
collected 1 item
test_foo.py F [100%]
==================================== FAILURES =====================================
____________________________________ test_foo _____________________________________
my_val = 'bar'
def test_foo(my_val):
> assert my_val == "foo"
E AssertionError: assert 'bar' == 'foo'
E
E - foo
E + bar
test_foo.py:2: AssertionError
============================= short test summary info =============================
FAILED test_foo.py::test_foo - AssertionError: assert 'bar' == 'foo'
================================ 1 failed in 0.01s ================================
$
第 2 步 - 添加 || 时|空
并重新组织项目,失败:
pyproject.toml
注释:
$ tree
.
├── my_project
│ └── my_tests
│ ├── conftest.py
│ ├── __init__.py
│ └── test_foo.py
└── pyproject.toml
3 directories, 4 files
$ pytest --foo bar
ERROR: usage: pytest [options] [file_or_dir] [file_or_dir] [...]
pytest: error: unrecognized arguments: --foo
inifile: /home/vmonteco/code/MREs/pytest__addoption__pyproject_toml/01_adding_pyproject_toml/pyproject.toml
rootdir: /home/vmonteco/code/MREs/pytest__addoption__pyproject_toml/01_adding_pyproject_toml
$
有疑问,我还添加了
-
文件。
__init__.py
尽管没有所需|,但 -
似乎被识别了| ||表,因此显然与
pyproject.toml
文档[tool.pytest.ini_options]
相矛盾。 但是,有一个简单的解决方法似乎在这种特定情况下有效: 只需手动将测试路径作为命令行参数传递给我的测试似乎足以使事情再次正常工作:
但我想避免这种情况,我宁愿正确配置我的项目。
第 3 步 - 尝试在
$ pytest --foo bar my_project/my_tests
=============================== test session starts ===============================
platform linux -- Python 3.10.13, pytest-8.1.1, pluggy-1.5.0
rootdir: /home/vmonteco/code/MREs/pytest__addoption__pyproject_toml/01_adding_pyproject_toml
configfile: pyproject.toml
collected 1 item
my_project/my_tests/test_foo.py F [100%]
==================================== FAILURES =====================================
____________________________________ test_foo _____________________________________
my_val = 'bar'
def test_foo(my_val):
> assert my_val == "foo"
E AssertionError: assert 'bar' == 'foo'
E
E - foo
E + bar
my_project/my_tests/test_foo.py:2: AssertionError
============================= short test summary info =============================
FAILED my_project/my_tests/test_foo.py::test_foo - AssertionError: assert 'bar' == 'foo'
================================ 1 failed in 0.02s ================================
$
中配置
失败。
testpaths
迄今为止我发现的最好的解释依赖于文档中的以下几点:
pyproject.toml
将 pytest_addoption 放在“初始”中的必要性
:
-
此钩子仅在初始conftests中调用。| ||pytest_addoption 文档
conftest.py
实际上什么是“初始
-
或
conftest.py
通过加载所有“初始”conftest.py文件:<test_path>/conftest.py
确定测试路径:在命令行上指定,否则在testpaths 如果已定义并从根目录运行,否则为每个测试路径的当前目录<test_test>/test*/conftest.py
,加载相对于测试路径的目录部分的conftest.py 和test*/conftest.py(如果存在)。在加载conftest.py文件之前,先加载其所有父目录中的conftest.py文件。加载 conftest.py 文件后,递归加载其 pytest_plugins 变量中指定的所有插件(如果存在)。- 工具启动时的插件发现顺序
- 所以,如果我理解得很好:
- 我的错误似乎会发生,因为如果我没有提供明确的测试路径,使用当前目录。但在这种情况下,我的
通过我的解决方法,显式传递更深的测试路径可以通过再次使conftest“初始”来解决此问题。
-
由此看来,尝试将我的命令行参数路径转换为一些配置(
conftest.py
)似乎是合适的,如 -
相关文档
中所示。
testpaths
但是当尝试再次运行我的命令时,我仍然遇到相同的错误:
我也尝试使用不同类型的配置文件:
但它仍然无法解决问题,尽管等效的命令行参数似乎有效。为什么?
But when trying to run my command again, I still get the same error:
$ cat pyproject.toml
[tool.pytest.ini_options]
testpaths = [
"my_project/my_tests",
]
$ tree
.
├── my_project
│ └── my_tests
│ ├── conftest.py
│ ├── __init__.py
│ └── test_foo.py
└── pyproject.toml
3 directories, 4 files
$ pytest --foo bar
ERROR: usage: pytest [options] [file_or_dir] [file_or_dir] [...]
pytest: error: unrecognized arguments: --foo
inifile: /home/vmonteco/code/MREs/pytest__addoption__pyproject_toml/02_attempt_to_solve/pyproject.toml
rootdir: /home/vmonteco/code/MREs/pytest__addoption__pyproject_toml/02_attempt_to_solve
$
I also tried to use a different kind of configuration file:
$ cat pytest.ini
[pytest]
testpaths = my_project/my_tests
$ pytest --foo bar
ERROR: usage: pytest [options] [file_or_dir] [file_or_dir] [...]
pytest: error: unrecognized arguments: --foo
inifile: /home/vmonteco/code/MREs/pytest__addoption__pyproject_toml/03_with_pytest_ini/pytest.ini
rootdir: /home/vmonteco/code/MREs/pytest__addoption__pyproject_toml/03_with_pytest_ini
$
But it still doesn't solve the problem despite the equivalent as command line argument seems to work. Why?
问题不在于你的
pytest_addoption
钩子,而在于你误解了
testpaths
的作用。
testpaths
选项不会告诉pytest在解析命令行参数
之前
在哪里查找测试。它告诉pytest在
之后
在哪里查找测试,如果没有在命令行上提供任何文件或目录。
发生的事情是,由于你没有在命令行上指定任何测试文件或目录,并且pytest无法识别
--foo
选项,因此它在运行任何测试之前失败,并显示“无法识别的参数”错误。
你有两种选择来解决此问题:
选项 1:始终在命令行上传递测试路径或文件名。 例如:
pytest --foo bar my_project/my_tests/
这很明确,可以让你完全控制要运行哪些测试。
选项 2:使用
addopts
选项在
pyproject.toml
或
pytest.ini
中指定默认测试路径,并在没有提供其他路径时运行。
例如,在
pyproject.toml
中:
[tool.pytest.ini_options]
addopts = "my_project/my_tests/"
testpaths = [
"my_project/my_tests",
]
这告诉pytest默认运行
my_project/my_tests/
目录中的测试,除非在命令行上另有指定。
使用这两种方法中的任何一种,你的
pytest_addoption
钩子都应该按预期工作,并且你的自定义
--foo
选项应该可以被识别。