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?

30voto

lmiguelvargasf Punkte 50452

Es gibt zwei Möglichkeiten, Ausnahmen in pytest zu behandeln:

  1. Verwendung von pytest.raises zum Schreiben von Behauptungen über aufgetretene Ausnahmen
  2. Verwendung von @pytest.mark.xfail

1. Verwendung von pytest.raises

Aus den Docs:

Um Behauptungen über aufgetretene Ausnahmen zu schreiben, können Sie pytest.raises als Kontext-Manager verwenden

Beispiele:

Nur eine Ausnahme behaupten:

import pytest

def test_zero_division():
    with pytest.raises(ZeroDivisionError):
        1 / 0

with pytest.raises(ZeroDivisionError) besagt, dass das, was auch immer im nächsten Block von Code ist, eine ZeroDivisionError Ausnahme auslösen sollte. Wenn keine Ausnahme auftritt, schlägt der Test fehl. Wenn der Test eine andere Ausnahme auslöst, schlägt er fehl.

Wenn Sie Zugriff auf die tatsächlichen Ausnahmeinformationen benötigen:

import pytest

def f():
    f()

def test_recursion_depth():
    with pytest.raises(RuntimeError) as excinfo:
        f()
    assert "maximum recursion" in str(excinfo.value)

excinfo ist eine ExceptionInfo Instanz, die ein Wrapper um die tatsächlich ausgelöste Ausnahme ist. Die wichtigsten Attribute sind .type, .value und .traceback.

2. Verwendung von @pytest.mark.xfail

Es ist auch möglich, ein raises Argument an pytest.mark.xfail zu übergeben.

import pytest

@pytest.mark.xfail(raises=IndexError)
def test_f():
    l = [1, 2, 3]
    l[10]

@pytest.mark.xfail(raises=IndexError) besagt, dass das, was auch immer im nächsten Block von Code ist, eine IndexError Ausnahme auslösen sollte. Wenn ein IndexError ausgelöst wird, wird der Test als xfailed (x) markiert. Wenn keine Ausnahme auftritt, wird der Test als xpassed (X) markiert. Wenn der Test eine andere Ausnahme auslöst, schlägt er fehl.

Anmerkungen:

  • Die Verwendung von pytest.raises ist wahrscheinlich besser für Fälle geeignet, in denen Sie Ausnahmen testen, die Ihr eigenes 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 ungefixten Fehlern oder Fehlern in Abhängigkeiten geeignet ist.

  • Sie können einen match Schlüsselwortparameter an den Kontext-Manager übergeben (pytest.raises), um zu testen, ob ein regulärer Ausdruck mit der Zeichenfolgenrepräsentation einer Ausnahme übereinstimmt. (mehr erfahren)

8voto

Alexey Shrub Punkte 970

Der richtige Weg ist die Verwendung von pytest.raises, aber ich habe einen interessanten alternativen Weg in den Kommentaren hier gefunden und möchte ihn für zukünftige Leser dieser Frage speichern:

try:
    thing_that_rasises_typeerror()
    assert False
except TypeError:
    assert True

5voto

SMDC Punkte 719

Dies ist die Lösung, die wir verwenden:

def test_date_invalidformat():
    """
    Testen, ob die Eingabe von falschen Daten eine ValueError-Ausnahme auslöst
    """
    date = "06/21/2018 00:00:00"
    with pytest.raises(ValueError):
        app.func(date) # meine zu testende Funktion

Bitte beachten Sie pytest, https://docs.pytest.org/en/latest/reference.html#pytest-raises

4voto

Elendurwen Punkte 882

Wenn Sie einen spezifischen Fehler testen möchten, verwenden Sie eine Kombination aus try, catch und raise:

#-- testen auf TypeError
try:
  myList.append_number("a")
  assert False
except TypeError: pass
except: assert False

2voto

rrlamichhane Punkte 1005

Die hier eingereichten Top-Antworten sind nützlich, wenn Sie erwarten, dass eine Ausnahme für Ihren Testfall ausgelöst wird. Es ist nicht sehr nützlich, wenn Ihr Test möglicherweise eine Ausnahme auslöst und Sie sie in beiden Szenarien elegant behandeln möchten.

Wenn Sie einen Testfall haben, der eine Ausnahme auslösen könnte (nicht wird), denke ich, dass dies eine bessere Option sein könnte.

@python.mark.parametrize("request_query, response_code", query_response_dataset)
def test_big_query_submission(request_query, response_code):
    try:
        stats = bigquery.Client().query(request_query)
    except Exception as e:
        assert False, f"Ausnahme ausgelöst: {e}"
    assert stats.errors is None

So sind Sie abgesichert, um einen Test graceful fehlschlagen zu lassen, anstatt einen Test für irgendeinen Grund durch eine ausgelöste Ausnahme abstürzen zu lassen.

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