我想使用fixture作为pytest.mark.parametrize
的参数或具有相同结果的东西。
例如:
import pytest
import my_package
@pytest.fixture
def dir1_fixture():
return '/dir1'
@pytest.fixture
def dir2_fixture():
return '/dir2'
@pytest.parametrize('dirname, expected', [(dir1_fixture, 'expected1'), (dir2_fixture, 'expected2')])
def test_directory_command(dirname, expected):
result = my_package.directory_command(dirname)
assert result == expected
fixture参数的问题是,每次使用fixture时,它的每个参数都会运行,但我不希望这样。我希望能够根据测试选择使用哪些固定装置。
Will在正确的路径上,您应该使用request.getfixturevalue
来检索fixture。
但你可以在测试中做对,这更简单。
@pytest.mark.parametrize('dirname, expected', [
('dir1_fixture', 'expected1'),
('dir2_fixture', 'expected2')])
def test_directory_command(dirname, expected, request):
result = my_package.directory_command(request.getfixturevalue(dirname))
assert result == expected
另一种方法是使用惰性固定装置插件:
@pytest.mark.parametrize('dirname, expected', [
(pytest.lazy_fixture('dir1_fixture'), 'expected1'),
(pytest.lazy_fixture('dir2_fixture'), 'expected2')])
def test_directory_command(dirname, expected):
result = my_package.directory_command(dirname)
assert result == expected
如果您使用的是pytest 3.0或更高版本,我认为您应该能够通过使用getfixturevalue
:编写一个fixture来解决这个特定的场景
@pytest.fixture(params=['dir1_fixture', 'dir2_fixture'])
def dirname(request):
return request.getfixturevalue(request.param)
但是,如果要动态加载的夹具已参数化,则不能使用此方法。
或者,您也可以使用pytest_generate_tests
钩子来解决一些问题。不过,我还没能让自己深入研究那么多。
pytest当前不支持此功能。不过,有一个开放功能请求(已于2013年开放)。
目前,我唯一的解决方案是创建一个返回fixture字典的fixture。
import pytest
import my_package
@pytest.fixture
def dir1_fixture():
return '/dir1'
@pytest.fixture
def dir2_fixture():
return '/dir2'
@pytest.fixture
def dir_fixtures(
dir1_fixture,
dir2_fixture
):
return {
'dir1_fixture': dir1_fixture,
'dir2_fixture': dir2_fixture
}
@pytest.mark.parametrize('fixture_name, expected', [('dir1_fixture', 'expected1'), ('dir2_fixture', 'expected2')])
def test_directory_command(dir_fixtures, fixture_name, expected):
dirname = dir_fixtures[fixture_name]
result = my_package.directory_command(dirname)
assert result == expected
不是最好的,因为它不使用pytest内置的解决方案,但它对我有效。
您可以使用一个参数化夹具,而不是两个不同的夹具,然后使用indirect
。
import pytest
import my_package
@pytest.fixture
def dirname(request):
return request.param
@pytest.mark.parametrize(
'dirname, expected',
[('/dir1', 'expected1'), ('/dir2', 'expected2')],
indirect=['dirname']
)
def test_directory_command(dirname, expected):
result = my_package.directory_command(dirname)
assert result == expected
在这种情况下,您可以使用请求(由于间接参数)对夹具进行参数化,expected
只是一个简单的参数
这可能偏离了主题,但我来这里是想弄清楚如何读取测试数据文件的整个目录,并将它们作为固定装置一个接一个地运行。所以,如果你把所有的目录都放在一个文件夹里,比如test/examples
,你可以做一些类似的事情:
import pytest
from pathlib import Path
@pytest.fixture(
# I guess this is anything that generates a list
# Make it a list of tuples if you want results as well, or JSON?
params=[str(p) for p in Path("test/examples").glob("*") if p.is_dir()]
)
def dirname(request):
return request.param
def test_directory_command(dirname): # dirname will be enumerated
result = my_package.directory_command(dirname)
assert ...
检查文档
例如,使用request.getfixturevalue(),您可以通过@pytest.mark.parameter()中设置的名称调用fruits()
和meat()
fixture,如下所示:
import pytest
@pytest.fixture
def fruits():
return "orange"
@pytest.fixture
def meat():
return "beef"
@pytest.mark.parametrize(
("food", "expected"),
(
("fruits", "orange"),
("meat", "beef")
)
)
def test(request, food, expected):
result = request.getfixturevalue(food) # Here
print(result, expected)
assert result == expected
然后,request.getfixturevalue()
可以通过@pytest.mark.parametrize()
中设置的名称调用fruits()
和meat()
fixture,如下所示:
$ pytest -q -rP
.. [100%]
=============== PASSES ================
_________ test[fruits-orange] _________
-------- Captured stdout call ---------
orange orange
___________ test[meat-beef] ___________
-------- Captured stdout call ---------
beef beef
2 passed in 0.10s
在测试执行期间不要试图更改夹具参数
无效示例:@pytest.ffixture(scope="class",params=other_fixture)
现在我将解释为什么它不起作用:
-
Pytest在运行测试之前创建会话对象,其中包含运行测试的参数。测试执行期间;您不能更改参数
-
如果您真的想这样做(动态更改参数),您可以使用一个中间文本文件:"params.txt">。示例:@pytest.ffixture(scope="class">params=json.load(open("topics.txt"))。同样,您将无法在测试期间更改文件的内容;因为如果你改变了它;将在测试中不可见。要做到这一点;我们需要在程序启动时和创建会话对象之前更改文件的内容。这样做;在更改文件内容的conftest.py中定义一个方法pytestrongessionstart(session)。
-
了解更多详细信息;查看以下文档:如何在所有类中的所有测试之前运行方法?和https://docs.pytest.org/en/6.2.x/reference.html#pytest.hookspec.pytestrongessionstart