863 Stimmen

Wie kann ich richtig behaupten, dass eine Ausnahme in pytest ausgelöst wird?

Code:

# coding=utf-8
import pytest

def whatever():
    return 9/0

def test_whatever():
    try:
        whatever()
    except ZeroDivisionError as exc:
        pytest.fail(exc, pytrace=True)

Output:

================================ test session starts =================================
platform linux2 -- Python 2.7.3 -- py-1.4.20 -- pytest-2.5.2
plugins: django, cov
collected 1 items 

pytest_test.py F

====================================== FAILURES ======================================
___________________________________ test_whatever ____________________________________

    def test_whatever():
        try:
            whatever()
        except ZeroDivisionError as exc:
>           pytest.fail(exc, pytrace=True)
E           Failed: integer division or modulo by zero

pytest_test.py:12: Failed
============================== 1 failed in 1.16 seconds ==============================

Wie kann ich pytest dazu bringen, den Traceback auszudrucken, damit ich sehen kann, wo in der whatever-Funktion eine Ausnahme ausgelöst wurde?

982voto

Murilo Giacometti Punkte 8890

pytest.raises(Ausnahme) ist das, was Sie brauchen.

Code

import pytest

def test_passes():
    with pytest.raises(Ausnahme) as e_info:
        x = 1 / 0

def test_passes_without_info():
    with pytest.raises(Ausnahme):
        x = 1 / 0

def test_fails():
    with pytest.raises(Ausnahme) as e_info:
        x = 1 / 1

def test_fails_without_info():
    with pytest.raises(Ausnahme):
        x = 1 / 1

# Tun Sie das nicht. Behauptungen werden als Ausnahmen erfasst.
def test_passes_but_should_not():
    try:
        x = 1 / 1
        assert False
    except Ausnahme:
        assert True

# Selbst wenn die entsprechende Ausnahme erfasst wird, ist es schlechter Stil,
# denn das Testergebnis ist weniger informativ
# als es mit pytest.raises(e) wäre
# (es sagt nur Bestanden oder Fehlgeschlagen.)

def test_passes_but_bad_style():
    try:
        x = 1 / 0
        assert False
    except ZeroDivisionError:
        assert True

def test_fails_but_bad_style():
    try:
        x = 1 / 1
        assert False
    except ZeroDivisionError:
        assert True

Output

============================================================================================= Testsession startet ==============================================================================================
Plattform Linux2 -- Python 2.7.6 -- py-1.4.26 -- pytest-2.6.4
gesammelt 7 Elemente 

test.py ..FF..F

================================================================================================== FEHLER ===================================================================================================
__________________________________________________________________________________________________ test_fails __________________________________________________________________________________________________

    def test_fails():
        with pytest.raises(Ausnahme) as e_info:
>           x = 1 / 1
E           Fehlgeschlagen: NICHT AUSGELÖST

test.py:13: Fehlgeschlagen
___________________________________________________________________________________________ test_fails_without_info ____________________________________________________________________________________________

    def test_fails_without_info():
        with pytest.raises(Ausnahme):
>           x = 1 / 1
E           Fehlgeschlagen: NICHT AUSGELÖST

test.py:17: Fehlgeschlagen
___________________________________________________________________________________________ test_fails_but_bad_style ___________________________________________________________________________________________

    def test_fails_but_bad_style():
        try:
            x = 1 / 1
>           assert False
E           assert False

test.py:43: AssertionError
====================================================================================== 3 fehlgeschlagen, 4 bestanden in 0.02 Sekunden ======================================================================================

Beachten Sie, dass e_info das Ausnahmeobjekt speichert, sodass Sie Details daraus extrahieren können. Zum Beispiel, wenn Sie den Ausnahmestapel oder eine andere verschachtelte Ausnahme überprüfen möchten.

362voto

simpleranchero Punkte 3704

Meinst du etwas in dieser Art:

def test_raises():
    with pytest.raises(Exception) as exc_info:   
        raise Exception('some info')
    # diese Asserts sind identisch; du kannst jedes verwenden   
    assert exc_info.value.args[0] == 'some info'
    assert str(exc_info.value) == 'some info'

275voto

Pytest entwickelt sich ständig weiter und mit einer der schönen Neuerungen in der jüngeren Vergangenheit ist es jetzt möglich, gleichzeitig zu testen für

  • den Ausnahmetyp (strenger Test)
  • die Fehlermeldung (strenger oder lockerer Check unter Verwendung eines regulären Ausdrucks)

Zwei Beispiele aus der Dokumentation:

with pytest.raises(ValueError, match='must be 0 or None'):
    raise ValueError('value must be 0 or None')

with pytest.raises(ValueError, match=r'must be \d+$'):
    raise ValueError('value must be 42')

Ich habe diesen Ansatz in einer Reihe von Projekten verwendet und mag ihn sehr.

Hinweis: Dieser Kommentar von ilya-rusin schlägt ebenfalls den oben genannten Ansatz vor.

99voto

veri_pudicha_coder Punkte 1167

Es gibt zwei Möglichkeiten, mit solchen Fällen in pytest umzugehen:

  • Verwendung der pytest.raises Funktion

  • Verwendung des pytest.mark.xfail Decorators

Wie es in der Dokumentation heißt:

Die Verwendung von pytest.raises ist wahrscheinlich besser für Fälle, in denen Sie Ausnahmen testen, die Ihr eigener Code absichtlich auslöst, während die Verwendung von @pytest.mark.xfail mit einer Prüffunktion wahrscheinlich besser für etwas wie das Dokumentieren von nicht behobenen Fehlern (wo der Test beschreibt, was eigentlich passieren sollte) oder Fehler in Abhängigkeiten ist.

Verwendung von pytest.raises:

def irgendwas():
    return 9/0
def test_irgendwas():
    with pytest.raises(ZeroDivisionError):
        irgendwas()

Verwendung von pytest.mark.xfail:

@pytest.mark.xfail(raises=ZeroDivisionError)
def test_irgendwas():
    irgendwas()

Ausgabe von pytest.raises:

============================= Testsession startet ============================
Plattform: Linux2 -- Python 2.7.10, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- 
/usr/local/python_2.7_10/bin/python
Cacheverzeichnis: .cache
Wurzelverzeichnis: /home/user, Inifile:
1 Sammlungselement

test_fun.py::test_irgendwas BESTANDEN

======================== 1 bestanden in 0.01 Sekunden =============================

Ausgabe des pytest.xfail Markers:

============================= Testsession startet ============================
Plattform: Linux2 -- Python 2.7.10, pytest-3.2.3, py-1.4.34, pluggy-0.4.0 -- 
/usr/local/python_2.7_10/bin/python
Cacheverzeichnis: .cache
Wurzelverzeichnis: /home/user, Inifile:
1 Sammlungselement

test_fun.py::test_irgendwas xfail

======================== 1 xfailed in 0.03 Sekunden ============================

65voto

d_j Punkte 1129

Du kannst versuchen

def test_exception():
    with pytest.raises(Exception) as excinfo:   
        function_that_raises_exception()   
    assert str(excinfo.value) == 'some info'

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X