pytest.mark.parametrize accepte un argument ids qui peut être appelable, comme ceci:
def test_id_builder(arg):
if isinstance(arg, int):
return str(arg)
... # more logic
@pytest.mark.parametrize('value', [1, 2], ids=test_id_builder)
def test_whatever(value):
assert value > 0
Cela en générera deux cas de test, avec les identifiants "1" et "2" respectivement. Le problème est que j'ai beaucoup de tests, organisés en plusieurs classes et fichiers. Pour cette raison, j'aimerais définir globalement test_id_builder comme fonction ids pour tous les tests paramétrés dans mon projet. Y a-t-il un moyen de faire cela?
3 Réponses :
Il n'y a aucun moyen de définir globalement des identifiants. mais vous pouvez utiliser pytest-generate-tests a > pour générer des tests à partir d'un autre appareil. cet autre appareil pourrait être étendu à la session , ce qui imitera globalement le comportement prévu.
Vous pouvez faire votre parametrize personnalisé :
old_parametrize = pytest.mark.parametrize
def custom_parametrize(*args, **kwargs):
kwargs.setdefault('ids', id_builder)
return old_parametrize(*args, **kwargs)
pytest.mark.parametrize = custom_parametrize
Et pour éviter de réécrire pytest.mark.parametrize en custom_parametrize utilise partout cette solution de contournement bien connue:
import pytest
def id_builder(arg):
if isinstance(arg, int):
return str(arg) * 2
def custom_parametrize(*args, **kwargs):
kwargs.setdefault('ids', id_builder)
return pytest.mark.parametrize(*args, **kwargs)
@custom_parametrize('value', [1, 2])
def test_whatever(value):
assert value > 0
Cela ressemble à une mauvaise conception ... mais je vais le prendre.
Mettez simplement en œuvre un pytest_make_parametrize_id code > crochet. Dans votre conftest.py:
$ pytest -q --collect-only test_spam.py::test_int[n=0] test_spam.py::test_int[n=1] test_spam.py::test_int[n=2] test_spam.py::test_str[text is fizz] test_spam.py::test_str[text is buzz] test_spam.py::test_unhandled[c0] test_spam.py::test_unhandled[c1] test_spam.py::test_unhandled[c2] no tests ran in 0.06 seconds
Exemples de tests:
import pytest
@pytest.mark.parametrize('n', range(3))
def test_int(n):
assert True
@pytest.mark.parametrize('s', ('fizz', 'buzz'))
def test_str(s):
assert True
@pytest.mark.parametrize('c', (tuple(), list(), set()))
def test_unhandled(c):
assert True
Vérifiez le paramétrage du test: p >
def pytest_make_parametrize_id(config, val, argname):
if isinstance(val, int):
return f'{argname}={val}'
if isinstance(val, str):
return f'text is {val}'
# return None to let pytest handle the formatting
return None
Maintenant ceci ressemble à une solution propre. Une chose, cependant: return val ne fonctionne que si val est une chaîne; selon la documentation, la manière correcte de laisser pytest le gérer est de retourner None .
@ Aran-Fey heureux de pouvoir vous aider! En fait, j'ai fait une erreur dans la réponse; return val doit être remplacé par return None si vous souhaitez déléguer la représentation arg à pytest . Mettra à jour la réponse.