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.parametrizeerkennen, dass die test_tc1Methode zwar kein Argument mit dem Namen verwendet tester_arg, das verwendete testerGerät dies jedoch tut, sodass das parametrisierte Argument durch das testerGerät weitergeleitet wird.
Ich hatte ein ähnliches Problem - ich habe ein Fixture namens test_packageund 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 versionArgument 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 versionArgument 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 MyTesterKlasse ein wenig umstrukturiert werden, damit ihr .argsAttribut nach dem Erstellen aktualisiert werden kann, um das Verhalten für einzelne Tests zu optimieren.