web-dev-qa-db-fra.com

Comment puis-je répéter chaque test plusieurs fois dans un cycle py.test?

Je veux exécuter chaque élément py.test sélectionné un nombre arbitraire de fois, séquentiellement.
Je ne vois aucun mécanisme py.test standard pour ce faire.

J'ai tenté de le faire dans le crochet pytest_collection_modifyitems(). J'ai modifié la liste des éléments transmis pour spécifier chaque élément plus d'une fois. La première exécution d'un élément de test fonctionne comme prévu, mais cela semble causer des problèmes pour mon code.

De plus, je préférerais avoir un objet d'élément de test unique pour chaque exécution, car j'utilise id (article) comme clé dans divers codes de rapport. Malheureusement, je ne trouve aucun code py.test pour dupliquer un élément de test, copy.copy() ne fonctionne pas et copy.deepcopy() obtient une exception.

Quelqu'un peut-il suggérer une stratégie pour exécuter un test plusieurs fois?

32
Martin Del Vecchio

Afin d'exécuter chaque test un certain nombre de fois, nous paramétrerons chaque test par programmation au fur et à mesure de leur génération.

Tout d'abord, ajoutons l'option analyseur (incluez les éléments suivants dans l'un de vos conftest.py's):

def pytest_addoption(parser):
    parser.addoption('--repeat', action='store',
        help='Number of times to repeat each test')

Nous ajoutons maintenant un crochet "pytest_generate_tests". C'est là que la magie opère.

def pytest_generate_tests(metafunc):
    if metafunc.config.option.repeat is not None:
        count = int(metafunc.config.option.repeat)

        # We're going to duplicate these tests by parametrizing them,
        # which requires that each test has a fixture to accept the parameter.
        # We can add a new fixture like so:
        metafunc.fixturenames.append('tmp_ct')

        # Now we parametrize. This is what happens when we do e.g.,
        # @pytest.mark.parametrize('tmp_ct', range(count))
        # def test_foo(): pass
        metafunc.parametrize('tmp_ct', range(count))

Courir sans le drapeau de répétition:

(env) $ py.test test.py -vv
============================= test session starts ==============================
platform darwin -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- env/bin/python
collected 2 items 

test.py:4: test_1 PASSED
test.py:8: test_2 PASSED

=========================== 2 passed in 0.01 seconds ===========================

Courir avec le drapeau de répétition:

(env) $ py.test test.py -vv --repeat 3
============================= test session starts ==============================
platform darwin -- Python 2.7.5 -- py-1.4.20 -- pytest-2.5.2 -- env/bin/python
collected 6 items 

test.py:4: test_1[0] PASSED
test.py:4: test_1[1] PASSED
test.py:4: test_1[2] PASSED
test.py:8: test_2[0] PASSED
test.py:8: test_2[1] PASSED
test.py:8: test_2[2] PASSED

=========================== 6 passed in 0.01 seconds ===========================

Lectures complémentaires:

13
Frank T

Le module pytest pytest-repeat existe à cet effet, et je recommande d'utiliser des modules dans la mesure du possible, plutôt que de réimplémenter vous-même leurs fonctionnalités.

Pour l'utiliser, ajoutez simplement pytest-repeat à ton requirements.txt ou pip install pytest-repeat, puis exécutez vos tests avec --count n.

37
jsj

Une stratégie possible consiste à paramétrer le test en question, mais sans utiliser explicitement le paramètre.

Par exemple:

@pytest.mark.parametrize('execution_number', range(5))
def run_multiple_times(execution_number):
    assert True

Le test ci-dessus doit être exécuté cinq fois.

Consultez la documentation de paramétrage: https://pytest.org/latest/parametrize.html

32
Frank T

Sur la base de la suggestion de Frank T, j'ai trouvé une solution très simple dans la légende pytest_generate_tests ():

parser.addoption ('--count', default=1, type='int', metavar='count', help='Run each test the specified number of times')

def pytest_generate_tests (metafunc):
    for i in range (metafunc.config.option.count):
        metafunc.addcall()

L'exécution de "py.test --count 5" entraîne l'exécution de chaque test cinq fois au cours de la session de test.

Et cela ne nécessite aucune modification de l'un de nos tests existants.

Merci Frank T!

7
Martin Del Vecchio

Sur la base de ce que j'ai vu ici, et étant donné que je fais déjà un filtrage des tests dans pytest_collection_modifyitems, ma méthode de choix est la suivante. Dans conftest.py

def pytest_addoption(parser):
    parser.addoption ('--count', default=1, type='int', metavar='count', help='Run each test the specified number of times')


def pytest_collection_modifyitems(session, config, items):
    count = config.option.count
    items[:] = items * count  # add each test multiple times
1
user7610