Atualização: uma vez que esta é a resposta aceita para esta pergunta e ainda recebe votos positivos às vezes, devo adicionar uma atualização. Embora a minha resposta original (abaixo) foi a única maneira de fazer isso em versões mais antigas do pytest como outros já observou pytest agora suporta parametrização indireta de acessórios. Por exemplo, você pode fazer algo assim (via @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
No entanto, embora essa forma de parametrização indireta seja explícita, como @Yukihiko Shinoda aponta, ela agora suporta uma forma de parametrização indireta implícita (embora eu não tenha conseguido encontrar nenhuma referência óbvia a isso nos documentos oficiais):
# 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
Não sei exatamente quais são as semânticas desse formulário, mas parece que pytest.mark.parametrizereconhece que embora o test_tc1método não receba um argumento chamado tester_arg, o testeracessório que está usando o faz, então ele passa o argumento parametrizado pelo testeracessório.
Eu tive um problema semelhante - eu tenho um acessório chamado test_packagee, mais tarde, quis ser capaz de passar um argumento opcional para aquele acessório ao executá-lo em testes específicos. Por exemplo:
@pytest.fixture()
def test_package(request, version='1.0'):
...
request.addfinalizer(fin)
...
return package
(Não importa para esses propósitos o que o aparelho faz ou que tipo de objeto retornado package) é.
Então, seria desejável usar de alguma forma esse acessório em uma função de teste de forma que eu também pudesse especificar o versionargumento daquele acessório para usar com esse teste. No momento, isso não é possível, embora possa ser um bom recurso.
Nesse ínterim, foi fácil fazer meu aparelho simplesmente retornar uma função que faz todo o trabalho que o aparelho fazia anteriormente, mas me permite especificar o versionargumento:
@pytest.fixture()
def test_package(request):
def make_test_package(version='1.0'):
...
request.addfinalizer(fin)
...
return test_package
return make_test_package
Agora posso usar isso em minha função de teste, como:
def test_install_package(test_package):
package = test_package(version='1.1')
...
assert ...
e assim por diante.
A tentativa de solução do OP estava indo na direção certa e, como sugere a resposta de @ hpk42 , ele MyTester.__init__poderia simplesmente armazenar uma referência à solicitação como:
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"
Em seguida, use isso para implementar o acessório como:
@pytest.fixture()
def tester(request):
""" create tester object """
# how to use the list below for arg?
_tester = MyTester(request)
return _tester
Se desejado, a MyTesterclasse pode ser reestruturada um pouco para que seu .argsatributo possa ser atualizado depois de ter sido criado, para ajustar o comportamento para testes individuais.