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.parametrize
reconhece que embora o test_tc1
método não receba um argumento chamado tester_arg
, o tester
acessório que está usando o faz, então ele passa o argumento parametrizado pelo tester
acessório.
Eu tive um problema semelhante - eu tenho um acessório chamado test_package
e, 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 version
argumento 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 version
argumento:
@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 MyTester
classe pode ser reestruturada um pouco para que seu .args
atributo possa ser atualizado depois de ter sido criado, para ajustar o comportamento para testes individuais.