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.parametrize
riconosca che sebbene il test_tc1
metodo non prenda un argomento denominato tester_arg
, il tester
dispositivo che sta utilizzando lo fa, quindi passa l'argomento parametrizzato attraverso il tester
dispositivo.
Ho avuto un problema simile: ho chiamato un dispositivo test_package
e 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' version
argomento 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' version
argomento:
@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 MyTester
classe potrebbe essere leggermente ristrutturata in modo che il suo .args
attributo possa essere aggiornato dopo che è stato creato, per modificare il comportamento per i singoli test.