更新:由于这是这个问题的公认答案,有时仍然会被点赞,我应该添加一个更新。尽管我最初的答案(下面)是在旧版本的pytest中做到这一点的唯一方法,因为其他人已经注意到pytest现在支持fixture的间接参数化。例如,你可以这样做(通过@imiric):
# test_parameterized_fixture.py
import pytest
class MyTester:
def __init__(self, x):
self.x = x
def dothis(self):
assert self.x
@pytest.fixture
def tester(request):
"""Create tester object"""
return MyTester(request.param)
class TestIt:
@pytest.mark.parametrize('tester', [True, False], indirect=['tester'])
def test_tc1(self, tester):
tester.dothis()
assert 1
$ pytest -v test_parameterized_fixture.py
================================================================================= test session starts =================================================================================
platform cygwin -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: .
collected 2 items
test_parameterized_fixture.py::TestIt::test_tc1[True] PASSED [ 50%]
test_parameterized_fixture.py::TestIt::test_tc1[False] FAILED
然而,尽管这种形式的间接参数化是明确的,正如@Yukihiko Shinoda指出的那样,它现在支持一种形式的隐性间接参数化(尽管我在官方文档中找不到任何明显的参考):
# test_parameterized_fixture2.py
import pytest
class MyTester:
def __init__(self, x):
self.x = x
def dothis(self):
assert self.x
@pytest.fixture
def tester(tester_arg):
"""Create tester object"""
return MyTester(tester_arg)
class TestIt:
@pytest.mark.parametrize('tester_arg', [True, False])
def test_tc1(self, tester):
tester.dothis()
assert 1
$ pytest -v test_parameterized_fixture2.py
================================================================================= test session starts =================================================================================
platform cygwin -- Python 3.6.8, pytest-5.3.1, py-1.8.0, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: .
collected 2 items
test_parameterized_fixture2.py::TestIt::test_tc1[True] PASSED [ 50%]
test_parameterized_fixture2.py::TestIt::test_tc1[False] FAILED
我不知道这种形式的确切语义是什么,但似乎pytest.mark.parametrize认识到,尽管test_tc1方法不接受名为test_arg的参数,但它使用的测试fixture接受,因此它通过测试fixture传递参数化参数。
我有一个类似的问题——我有一个名为test_package的fixture,后来我希望在特定测试中运行该fixture时能够将一个可选参数传递给它。例如:
@pytest.fixture()
def test_package(request, version='1.0'):
...
request.addfinalizer(fin)
...
return package
(对于这些目的,fixture做什么或返回的包是什么类型的对象并不重要)。
然后,希望以某种方式在测试函数中使用这个fixture,这样我也可以指定该fixture的版本参数,以便与该测试一起使用。这目前是不可能的,尽管可能是一个不错的功能。
与此同时,让我的fixture简单地返回一个函数来完成之前fixture所做的所有工作是很容易的,但允许我指定version参数:
@pytest.fixture()
def test_package(request):
def make_test_package(version='1.0'):
...
request.addfinalizer(fin)
...
return test_package
return make_test_package
现在我可以在我的测试函数中使用它:
def test_install_package(test_package):
package = test_package(version='1.1')
...
assert ...
等等。
OP尝试的解决方案朝着正确的方向前进,正如@hpk42的回答所表明的那样,我的测试者。__init__可以像这样存储对请求的引用:
class MyTester(object):
def __init__(self, request, arg=["var0", "var1"]):
self.request = request
self.arg = arg
# self.use_arg_to_init_logging_part()
def dothis(self):
print "this"
def dothat(self):
print "that"
然后使用这个来实现像这样的夹具:
@pytest.fixture()
def tester(request):
""" create tester object """
# how to use the list below for arg?
_tester = MyTester(request)
return _tester
如果需要,可以稍微重新构造MyTester类,以便在创建后更新它的.args属性,以调整单个测试的行为。