web-dev-qa-db-fra.com

Comment exécuter tous les tests PyTest même si certains d'entre eux échouent?

Je cherche un moyen d'exécuter tous mes tests unitaires dans PyTest, même si certains échouent. Je sais qu'il doit y avoir un moyen simple de le faire. J'ai vérifié les options CLi et cherché sur ce site des questions/réponses similaires, mais je n'ai rien vu. Désolé si cela a déjà été répondu.

Par exemple, considérez l'extrait de code suivant, avec le code PyTest à côté:

def parrot(i):
    return i

def test_parrot():
    assert parrot(0) == 0
    assert parrot(1) == 1
    assert parrot(2) == 1
    assert parrot(2) == 2

Par défaut, l'exécution s'arrête au premier échec:

$ python -m pytest fail_me.py 
=================== test session starts ===================
platform linux2 -- Python 2.7.10, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: /home/npsrt/Documents/repo/codewars, inifile: 
collected 1 items 

fail_me.py F

=================== FAILURES ===================
___________________ test_parrot ___________________

    def test_parrot():
        assert parrot(0) == 0
        assert parrot(1) == 1
>       assert parrot(2) == 1
E       assert 2 == 1
E        +  where 2 = parrot(2)

fail_me.py:7: AssertionError
=================== 1 failed in 0.05 seconds ===================

Ce que j'aimerais faire, c'est que le code continue de s'exécuter même après que PyTest rencontre le premier échec.

16
Jeff Wright

Il a exécuté tous vos tests. Vous n'avez écrit qu'un seul test, et ce test a fonctionné!

Si vous voulez des assertions non fatales, où un test continuera si une assertion échoue (comme les macros EXPECT de Google Test), essayez pytest-expect , qui fournit cette fonctionnalité. Voici l'exemple donné par leur site:

def test_func(expect):
    expect('a' == 'b')
    expect(1 != 1)
    a = 1
    b = 2
    expect(a == b, 'a:%s b:%s' % (a,b))

Vous pouvez voir que les échecs des attentes n'arrêtent pas le test, et toutes les attentes échouées sont signalées:

$ python -m pytest test_expect.py
================ test session starts =================
platform darwin -- Python 2.7.9 -- py-1.4.26 -- pytest-2.7.0
rootdir: /Users/okken/example, inifile: 
plugins: expect
collected 1 items 

test_expect.py F

====================== FAILURES ======================
_____________________ test_func ______________________
>    expect('a' == 'b')
test_expect.py:2
--------
>    expect(1 != 1)
test_expect.py:3
--------
>    expect(a == b, 'a:%s b:%s' % (a,b))
a:1 b:2
test_expect.py:6
--------
Failed Expectations:3
============== 1 failed in 0.01 seconds ==============

Comme d'autres l'ont déjà mentionné, vous devriez idéalement écrire plusieurs tests et n'avoir qu'une seule assertion dans chacun (ce n'est pas une limite stricte, mais une bonne ligne directrice).

Le @pytest.mark.parametrize décorateur rend cela facile:

import pytest

def parrot(i):
    return i

@pytest.mark.parametrize('inp, expected', [(0, 0), (1, 1), (2, 1), (2, 2)])
def test_parrot(inp, expected):
    assert parrot(inp) == expected

Lorsque vous l'exécutez avec -v:

parrot.py::test_parrot[0-0] PASSED
parrot.py::test_parrot[1-1] PASSED
parrot.py::test_parrot[2-1] FAILED
parrot.py::test_parrot[2-2] PASSED

=================================== FAILURES ===================================
_______________________________ test_parrot[2-1] _______________________________

inp = 2, expected = 1

    @pytest.mark.parametrize('inp, expected', [(0, 0), (1, 1), (2, 1), (2, 2)])
    def test_parrot(inp, expected):
>       assert parrot(inp) == expected
E       assert 2 == 1
E        +  where 2 = parrot(2)

parrot.py:8: AssertionError
====================== 1 failed, 3 passed in 0.01 seconds ======================
11
The Compiler

Vous devriez pouvoir contrôler cela avec le --maxfail argument. Je crois que la valeur par défaut est de ne pas s'arrêter pour les échecs, donc je vérifierais tous les fichiers de configuration py.test que vous pourriez avoir pour un endroit qui le remplace.

7
Daenyth

Le plugin pytest pytest-check est une réécriture de pytest-expect (qui a été recommandée ici précédemment mais est devenue obsolète). Cela vous permettra de faire une affirmation "douce" comme ceci:

Un exemple du dépôt GitHub:

import pytest_check as check

def test_example():
    a = 1
    b = 2
    c = [2, 4, 6]
    check.greater(a, b)
    check.less_equal(b, a)
    check.is_in(a, c, "Is 1 in the list")
    check.is_not_in(b, c, "make sure 2 isn't in list")
2
ChrisGS