Обновление: поскольку это принятый ответ на этот вопрос, и он по-прежнему иногда получает одобрение, я должен добавить обновление. Хотя мой первоначальный ответ (ниже) был единственным способом сделать это в более старых версиях pytest , как другие уже отметил pytest теперь поддерживает косвенную параметризацию светильников. Например, вы можете сделать что-то вроде этого (через @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
метод не принимает аргумент с именем tester_arg
, его использует tester
прибор, который он использует, поэтому он передает параметризованный аргумент через tester
прибор.
У меня была аналогичная проблема - у меня вызывается прибор test_package
, и позже я хотел иметь возможность передавать необязательный аргумент этому приспособлению при его запуске в определенных тестах. Например:
@pytest.fixture()
def test_package(request, version='1.0'):
...
request.addfinalizer(fin)
...
return package
(Для этих целей не имеет значения, что делает прибор или какой тип возвращаемого объекта package
).
Тогда было бы желательно каким-то образом использовать это приспособление в тестовой функции таким образом, чтобы я мог также указать version
аргумент этого приспособления для использования с этим тестом. В настоящее время это невозможно, хотя это может быть хорошей функцией.
Тем временем было достаточно легко заставить мой прибор просто возвращать функцию, которая выполняет всю работу, которую ранее выполняла прибор, но позволяет мне указать 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 , MyTester.__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
атрибут можно было обновить после того, как он был создан, чтобы настроить поведение для отдельных тестов.