Update: Da dies die akzeptierte Antwort auf diese Frage ist und manchmal immer noch positiv bewertet wird, sollte ich ein Update hinzufügen. Obwohl meine ursprüngliche Antwort (unten) die einzige Möglichkeit war, dies in älteren Versionen von pytest zu tun, wie andere festgestellt haben , unterstützt pytest jetzt die indirekte Parametrisierung von Vorrichtungen. Zum Beispiel können Sie so etwas tun (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
Obwohl diese Form der indirekten Parametrisierung explizit ist, unterstützt @Yukihiko Shinoda, wie sie betont , jetzt eine Form der impliziten indirekten Parametrisierung (obwohl ich in den offiziellen Dokumenten keinen offensichtlichen Hinweis darauf finden konnte):
# 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
Ich weiß nicht genau, wie die Semantik dieses Formulars aussieht, aber es scheint zu pytest.mark.parametrize
erkennen, dass die test_tc1
Methode zwar kein Argument mit dem Namen verwendet tester_arg
, das verwendete tester
Gerät dies jedoch tut, sodass das parametrisierte Argument durch das tester
Gerät weitergeleitet wird.
Ich hatte ein ähnliches Problem - ich habe ein Fixture namens test_package
und wollte später in der Lage sein, diesem Fixture ein optionales Argument zu übergeben, wenn es in bestimmten Tests ausgeführt wird. Beispielsweise:
@pytest.fixture()
def test_package(request, version='1.0'):
...
request.addfinalizer(fin)
...
return package
(Für diese Zwecke spielt es keine Rolle, was das Gerät tut oder welche Art von Objekt das zurückgegebene ist package
).
Es wäre dann wünschenswert, dieses Gerät irgendwie in einer Testfunktion so zu verwenden, dass ich auch das version
Argument für dieses Gerät angeben kann, das mit diesem Test verwendet werden soll. Dies ist derzeit nicht möglich, könnte aber eine nette Funktion sein.
In der Zwischenzeit war es einfach genug, mein Gerät dazu zu bringen, einfach eine Funktion zurückzugeben , die die gesamte Arbeit des Geräts erledigt, aber mir erlaubt, das folgende version
Argument anzugeben :
@pytest.fixture()
def test_package(request):
def make_test_package(version='1.0'):
...
request.addfinalizer(fin)
...
return test_package
return make_test_package
Jetzt kann ich dies in meiner Testfunktion verwenden wie:
def test_install_package(test_package):
package = test_package(version='1.1')
...
assert ...
und so weiter.
Der Lösungsversuch des OP ging in die richtige Richtung, und wie aus der Antwort von @ hpk42 hervorgeht , MyTester.__init__
könnte der Verweis auf die Anfrage einfach wie folgt gespeichert werden:
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"
Verwenden Sie dies dann, um das Gerät wie folgt zu implementieren:
@pytest.fixture()
def tester(request):
""" create tester object """
# how to use the list below for arg?
_tester = MyTester(request)
return _tester
Falls gewünscht, kann die MyTester
Klasse ein wenig umstrukturiert werden, damit ihr .args
Attribut nach dem Erstellen aktualisiert werden kann, um das Verhalten für einzelne Tests zu optimieren.