3
votes

Est-il possible de définir globalement une fonction `ids` par défaut pour le paramétrage de pytest?

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?


0 commentaires

3 Réponses :



2
votes

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


1 commentaires

Cela ressemble à une mauvaise conception ... mais je vais le prendre.



4
votes

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


2 commentaires

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.