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.