Aggiornamento: poiché questa è la risposta accettata a questa domanda e viene ancora votata a volte, dovrei aggiungere un aggiornamento. Sebbene la mia risposta originale (sotto) fosse l'unico modo per farlo nelle versioni precedenti di pytest, poiché altri hanno notato che pytest ora supporta la parametrizzazione indiretta dei dispositivi. Ad esempio puoi fare qualcosa del genere (tramite @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
Tuttavia, anche se questa forma di parametrizzazione indiretta è esplicito, come @Yukihiko Shinoda sottolinea che ora supporta una forma di implicita parametrizzazione indiretta (anche se non ho potuto trovare alcun riferimento ovvia a questo nella documentazione ufficiale):
# 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
Non so esattamente quali siano le semantiche di questo modulo, ma sembra che pytest.mark.parametrizericonosca che sebbene il test_tc1metodo non prenda un argomento denominato tester_arg, il testerdispositivo che sta utilizzando lo fa, quindi passa l'argomento parametrizzato attraverso il testerdispositivo.
Ho avuto un problema simile: ho chiamato un dispositivo test_packagee in seguito ho voluto essere in grado di passare un argomento opzionale a quel dispositivo durante l'esecuzione in test specifici. Per esempio:
@pytest.fixture()
def test_package(request, version='1.0'):
...
request.addfinalizer(fin)
...
return package
(Non importa per questi scopi cosa fa il dispositivo o quale tipo di oggetto viene restituito package).
Sarebbe quindi desiderabile utilizzare in qualche modo questo dispositivo in una funzione di test in modo tale da poter anche specificare l' versionargomento di quel dispositivo da utilizzare con quel test. Questo non è attualmente possibile, anche se potrebbe essere una bella funzionalità.
Nel frattempo è stato abbastanza facile fare in modo che il mio dispositivo restituisse semplicemente una funzione che fa tutto il lavoro svolto in precedenza dal dispositivo, ma mi permette di specificare l' versionargomento:
@pytest.fixture()
def test_package(request):
def make_test_package(version='1.0'):
...
request.addfinalizer(fin)
...
return test_package
return make_test_package
Ora posso usarlo nella mia funzione di test come:
def test_install_package(test_package):
package = test_package(version='1.1')
...
assert ...
e così via.
La soluzione tentata dall'OP andava nella giusta direzione e, come suggerisce la risposta di @ hpk42 , MyTester.__init__potrebbe semplicemente memorizzare un riferimento alla richiesta come:
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"
Quindi usalo per implementare il dispositivo come:
@pytest.fixture()
def tester(request):
""" create tester object """
# how to use the list below for arg?
_tester = MyTester(request)
return _tester
Se lo si desidera, la MyTesterclasse potrebbe essere leggermente ristrutturata in modo che il suo .argsattributo possa essere aggiornato dopo che è stato creato, per modificare il comportamento per i singoli test.