Pembaruan: Karena ini adalah jawaban yang diterima untuk pertanyaan ini dan kadang-kadang masih mendapat suara positif, saya harus menambahkan pembaruan. Meskipun jawaban asli saya (di bawah) adalah satu-satunya cara untuk melakukan ini di versi pytest yang lebih lama karena yang lain telah mencatat pytest sekarang mendukung parametriisasi perlengkapan tidak langsung. Misalnya Anda dapat melakukan sesuatu seperti ini (melalui @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
Namun, meskipun bentuk parametrization tidak langsung adalah eksplisit, seperti @Yukihiko Shinoda menunjukkan sekarang mendukung bentuk parametrization tidak langsung implisit (meskipun saya tidak bisa menemukan referensi yang jelas untuk ini di dokumentasi resmi):
# 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
Saya tidak tahu persis apa semantik dari formulir ini, tetapi tampaknya pytest.mark.parametrize
mengakui bahwa meskipun test_tc1
metode tidak mengambil argumen bernama tester_arg
, tester
fixture yang digunakan tidak, sehingga meneruskan argumen parametrized melalui tester
fixture.
Saya memiliki masalah yang sama - saya memiliki fixture yang dipanggil test_package
, dan saya kemudian ingin memberikan argumen opsional ke fixture tersebut saat menjalankannya dalam tes tertentu. Sebagai contoh:
@pytest.fixture()
def test_package(request, version='1.0'):
...
request.addfinalizer(fin)
...
return package
(Tidak masalah untuk tujuan ini apa yang dilakukan fixture atau jenis objek yang dikembalikan package
).
Maka akan diinginkan untuk entah bagaimana menggunakan perlengkapan ini dalam fungsi uji sedemikian rupa sehingga saya juga dapat menentukan version
argumen ke perlengkapan itu untuk digunakan dengan tes itu. Ini saat ini tidak memungkinkan, meskipun mungkin merupakan fitur yang bagus.
Sementara itu, cukup mudah untuk membuat perlengkapan saya mengembalikan fungsi yang melakukan semua pekerjaan fixture sebelumnya, tetapi memungkinkan saya untuk menentukan version
argumen:
@pytest.fixture()
def test_package(request):
def make_test_package(version='1.0'):
...
request.addfinalizer(fin)
...
return test_package
return make_test_package
Sekarang saya dapat menggunakan ini dalam fungsi pengujian saya seperti:
def test_install_package(test_package):
package = test_package(version='1.1')
...
assert ...
dan seterusnya.
Solusi yang dicoba OP sedang menuju ke arah yang benar, dan seperti yang disarankan oleh jawaban @ hpk42 , MyTester.__init__
itu hanya dapat menyimpan referensi ke permintaan seperti:
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"
Kemudian gunakan ini untuk mengimplementasikan perlengkapan seperti:
@pytest.fixture()
def tester(request):
""" create tester object """
# how to use the list below for arg?
_tester = MyTester(request)
return _tester
Jika diinginkan, MyTester
kelas dapat direstrukturisasi sedikit sehingga .args
atributnya dapat diperbarui setelah dibuat, untuk menyesuaikan perilaku pengujian individual.
Ini sebenarnya didukung secara native di py.test melalui parametrization tidak langsung .
Dalam kasus Anda, Anda akan memiliki:
sumber
indirect
argumen kata kunci diakui jarang dan tidak ramah, yang mungkin account untuk ketidakjelasan teknik penting ini. Saya telah menjelajahi situs py.test pada beberapa kesempatan untuk fitur ini - hanya untuk tampil kosong, lebih tua, dan bingung. Kepahitan adalah tempat yang dikenal sebagai integrasi berkelanjutan. Terima kasih Odin untuk Stackoverflow.test_tc1
menjaditest_tc1[tester0]
.indirect=True
serahkan parameter ke semua perlengkapan yang disebut, bukan? Karena dokumentasi secara eksplisit menamai perlengkapan untuk parametrikisasi tidak langsung, misalnya untuk perlengkapan bernamax
:indirect=['x']
Anda dapat mengakses modul / kelas / fungsi yang meminta dari fungsi perlengkapan (dan dengan demikian dari kelas Penguji Anda), lihat berinteraksi dengan meminta konteks pengujian dari fungsi perlengkapan . Jadi Anda dapat mendeklarasikan beberapa parameter pada kelas atau modul dan perlengkapan penguji dapat mengambilnya.
sumber
@fixture def my_fixture(request)
dan kemudian@pass_args(arg1=..., arg2=...) def test(my_fixture)
mendapatkan argumenmy_fixture()
seperti iniarg1 = request.arg1, arg2 = request.arg2
. Apakah hal seperti ini mungkin terjadi di py.test sekarang?Saya tidak dapat menemukan dokumen apa pun, namun tampaknya berfungsi di versi terbaru pytest.
sumber
Nadège
telah dikembalikan. Jadi, fitur tidak berdokumen ini (menurut saya masih tidak terdokumentasi?) Masih hidup.Untuk meningkatkan jawaban imiric sedikit : cara elegan lain untuk memecahkan masalah ini adalah dengan membuat "perlengkapan parameter". Saya pribadi lebih suka
indirect
fitur ini daripadapytest
. Fitur ini tersedia daripytest_cases
, dan ide aslinya disarankan oleh Sup3rGeo .Perhatikan bahwa
pytest-cases
juga menyediakan@pytest_fixture_plus
yang memungkinkan Anda untuk menggunakan tanda parametrization pada perlengkapan Anda, dan@cases_data
yang memungkinkan Anda untuk sumber parameter Anda dari fungsi dalam modul terpisah. Lihat dok untuk detailnya. Ngomong-ngomong, saya adalah penulisnya;)sumber
param_fixture
. Lihat jawaban ini . Saya tidak bisa menemukan contoh seperti itu di dokumen; apakah kamu tahu sesuatu tentang ini?Saya membuat dekorator lucu yang memungkinkan perlengkapan menulis seperti ini:
Di sini, di sebelah kiri
/
Anda memiliki perlengkapan lain, dan di sebelah kanan Anda memiliki parameter yang disediakan menggunakan:Ini bekerja dengan cara yang sama seperti fungsi argumen bekerja. Jika Anda tidak memberikan
age
argumen, argumen default69
,, akan digunakan. jika Anda tidak menyediakanname
, atau menghilangkandog.arguments
dekorator, Anda mendapatkan yang biasaTypeError: dog() missing 1 required positional argument: 'name'
. Jika Anda memiliki perlengkapan lain yang membutuhkan argumenname
, itu tidak bertentangan dengan yang satu ini.Perlengkapan Async juga didukung.
Selain itu, ini memberi Anda rencana penyiapan yang bagus:
Contoh lengkapnya:
Kode untuk dekorator:
sumber