Nehmen wir an, wir haben so etwas:

import py, pytest

ERROR1 = ' --- Error : value < 5! ---'
ERROR2 = ' --- Error : value > 10! ---'

class MyError(Exception):
    def __init__(self, m):
        self.m = m

    def __str__(self):
        return self.m

def foo(i):
    if i < 5:
        raise MyError(ERROR1)
    elif i > 10:
        raise MyError(ERROR2)
    return i


# ---------------------- TESTS -------------------------
def test_foo1():
    with pytest.raises(MyError) as e:
        foo(3)
    assert ERROR1 in str(e)

def test_foo2():
    with pytest.raises(MyError) as e:
        foo(11)
    assert ERROR2 in str(e)

def test_foo3():
        ....
        foo(7)
         ....

F: Wie kann ich test_foo3 () dazu bringen, zu testen, dass kein MyError ausgelöst wird? Es ist offensichtlich, dass ich nur testen konnte:

def test_foo3():
    assert foo(7) == 7

Aber ich möchte das über pytest.raises () testen. Ist das irgendwie möglich? Zum Beispiel: In einem Fall hat diese Funktion "foo" überhaupt keinen Rückgabewert.

def foo(i):
    if i < 5:
        raise MyError(ERROR1)
    elif i > 10:
        raise MyError(ERROR2)

Es könnte sinnvoll sein, diesen Weg zu testen, imho.

89
paraklet 29 Nov. 2013 im 01:29

3 Antworten

Beste Antwort

Ein Test schlägt fehl, wenn eine unerwartete Ausnahme ausgelöst wird. Sie können einfach foo (7) aufrufen und haben getestet, dass kein MyError ausgelöst wird. Folgendes wird also ausreichen:

def test_foo3():
    foo(7)

Wenn Sie explizit sein und eine Assert-Anweisung dafür schreiben möchten, können Sie Folgendes tun:

def test_foo3():
    try:
        foo(7)
    except MyError:
        pytest.fail("Unexpected MyError ..")
101
Faruk Sahin 12 Apr. 2018 im 09:52

Aufbauend auf dem, was Oisin erwähnt hat.

Sie können eine einfache not_raises -Funktion erstellen, die sich ähnlich wie die raises von pytest verhält:

from contextlib import contextmanager

@contextmanager
def not_raises(exception):
  try:
    yield
  except exception:
    raise pytest.fail("DID RAISE {0}".format(exception))

Dies ist in Ordnung, wenn Sie daran festhalten möchten, dass raises ein Gegenstück hat und Ihre Tests daher besser lesbar sind. Im Wesentlichen benötigen Sie jedoch nichts anderes, als nur den Codeblock auszuführen, den Sie in einer eigenen Zeile testen möchten - pytest schlägt ohnehin fehl, sobald dieser Block einen Fehler auslöst.

13
Pithikos 11 Okt. 2017 im 14:11

Ich war gespannt, ob ein not_raises funktionieren würde. Ein schneller Test hierfür ist (test_notraises.py):

from contextlib import contextmanager

@contextmanager
def not_raises(ExpectedException):
    try:
        yield

    except ExpectedException, err:
        raise AssertionError(
            "Did raise exception {0} when it should not!".format(
                repr(ExpectedException)
            )
        )

    except Exception, err:
        raise AssertionError(
            "An unexpected exception {0} raised.".format(repr(err))
        )

def good_func():
    print "hello"


def bad_func():
    raise ValueError("BOOM!")


def ugly_func():
    raise IndexError("UNEXPECTED BOOM!")


def test_ok():
    with not_raises(ValueError):
        good_func()


def test_bad():
    with not_raises(ValueError):
        bad_func()


def test_ugly():
    with not_raises(ValueError):
        ugly_func()

Es scheint zu funktionieren. Ich bin mir jedoch nicht sicher, ob es im Test wirklich gut liest.

6
Oisin 17 Feb. 2016 im 13:37