Aktualizacja: Ponieważ jest to zaakceptowana odpowiedź na to pytanie i czasami jest przegłosowana, powinienem dodać aktualizację. Mimo, że mój oryginalny odpowiedź (poniżej) było jedynym sposobem, aby to zrobić w starszych wersjach pytest jak inni nie zauważyć pytest teraz obsługuje pośrednie parametryzacji urządzeń. Na przykład możesz zrobić coś takiego (przez @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
Jednak, chociaż ta forma parametryzacji pośredniej jest wyraźna, jak wskazuje @Yukihiko Shinoda , obsługuje ona teraz formę niejawnej parametryzacji pośredniej (chociaż nie mogłem znaleźć żadnego oczywistego odniesienia do tego w oficjalnych dokumentach):
# 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
Nie wiem dokładnie, jaka jest semantyka tego formularza, ale wydaje się, że pytest.mark.parametrize
rozpoznaje, że chociaż test_tc1
metoda nie przyjmuje argumentu o nazwie tester_arg
, tester
urządzenie, którego używa, robi, więc przekazuje sparametryzowany argument dalej przez tester
urządzenie.
Miałem podobny problem - mam wywołane urządzenie test_package
, a później chciałem móc przekazać opcjonalny argument do tego urządzenia podczas uruchamiania go w określonych testach. Na przykład:
@pytest.fixture()
def test_package(request, version='1.0'):
...
request.addfinalizer(fin)
...
return package
(Dla tych celów nie ma znaczenia, co robi urządzenie lub jaki typ zwracanego obiektu package
).
Byłoby zatem pożądane, aby w jakiś sposób użyć tego urządzenia w funkcji testowej w taki sposób, żebym mógł również określić version
argument dla tego urządzenia do użycia w tym teście. Obecnie nie jest to możliwe, ale może być fajną funkcją.
W międzyczasie łatwo było sprawić, że moje urządzenie po prostu zwróciło funkcję, która wykonuje całą pracę, jaką wykonało wcześniej urządzenie, ale pozwala mi określić version
argument:
@pytest.fixture()
def test_package(request):
def make_test_package(version='1.0'):
...
request.addfinalizer(fin)
...
return test_package
return make_test_package
Teraz mogę użyć tego w mojej funkcji testowej, takiej jak:
def test_install_package(test_package):
package = test_package(version='1.1')
...
assert ...
i tak dalej.
Próba rozwiązania OP zmierzała we właściwym kierunku i, jak sugeruje odpowiedź @ hpk42 , MyTester.__init__
można po prostu zapisać odniesienie do żądania, takie jak:
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"
Następnie użyj tego, aby zaimplementować urządzenie, takie jak:
@pytest.fixture()
def tester(request):
""" create tester object """
# how to use the list below for arg?
_tester = MyTester(request)
return _tester
W razie potrzeby MyTester
klasę można nieco przebudować, aby jej .args
atrybut mógł zostać zaktualizowany po jej utworzeniu, aby dostosować zachowanie dla poszczególnych testów.