2013-11-28 10 views
19
angehoben

Nehmen wir an, wir haben smth wie folgt aus:Wie pytest verwenden, die Fehler überprüfen NICHT

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) 
     .... 

Q: Wie kann ich test_foo3() machen zu testen, dass kein MyError erhoben wird? Es ist offensichtlich, dass ich konnte einfach Test:

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

, aber ich, dass über pytest.raises testen möchten(). Ist das irgendwie möglich? Zum Beispiel: in einem Fall, dass die Funktion „foo“ haben keinen Rückgabewert überhaupt,

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

es Sinn machen könnte auf diese Weise zu testen, imho.

+0

Es sieht so aus, als würde man nach einem Problem suchen, der Code Test 'foo (7)' ist in Ordnung. Sie erhalten die richtige Nachricht und es ist einfacher, mit allen pytest-Ausgaben zu debuggen. Der Vorschlag, den Sie von @Faruk ("Unerwarteter Fehler ...") erzwungen haben, sagt nichts über den Fehler aus und Sie bleiben stecken. Das einzige, was Sie tun können, um es besser zu machen, ist, Ihre Absicht wie 'test_foo3_works_on_integers_within_range()' anzugeben. – dhill

Antwort

36

Ein Test wird fehlschlagen, wenn er irgendeine unerwartete Ausnahme auslöst. Sie können einfach foo (7) aufrufen und Sie werden getestet haben, dass kein MyError ausgelöst wird. So genügt folgendes:

def test_foo3(): 
    foo(7) 

Wenn Sie wirklich eine assert-Anweisung für diese schreiben möchten, können Sie versuchen:

def test_foo3(): 
    try: 
     foo(7) 
    except MyError: 
     pytest.fail("Unexpected MyError ..") 
+0

Danke, es funktioniert, aber es scheint eher ein Hack, als eine saubere Lösung. Zum Beispiel wird der Test für foo (4) fehlschlagen, aber nicht aufgrund eines Assertionsfehlers. – paraklet

+0

Test für foo (4) wird fehlschlagen, weil es eine Ausnahme auslöst, die nicht erwartet wurde. Ein anderer Weg wäre, es in einen try catch-Block zu packen und mit einer bestimmten Nachricht zu scheitern. Ich werde meine Antwort aktualisieren. –

+0

Wenn Sie eine Menge von Fällen wie diesen kann es sinnvoll sein, dass in einer einfachen Funktion zu schreiben: '' ' def not_raises (error_class, func, * args, ** kwargs): ... ' ' ' Oder Sie können einen mit ähnlichen Ansatz wie Pytest schreiben. Wenn du das tust, schlage ich vor, dass du eine PR schreibst, um allen zu helfen. :) (Das Repository befindet sich in [bitbucket] (https://bitbucket.org/hpk42/pytest)). –

3

Ich war neugierig zu sehen, ob ein not_raises funktionieren würde. Ein schneller Test dafü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 zu funktionieren scheint. Allerdings bin ich mir nicht sicher, ob es im Test wirklich gut liest.

3

Gebäude auf, was Oisin erwähnt ..

Sie können eine einfache not_raises Funktion machen, die ähnlich wirkt pytest des raises:

from contextlib import contextmanager 

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

Das ist in Ordnung, wenn Sie mit raises haften möchten mit ein Gegenstück und somit sind Ihre Tests besser lesbar. Im Wesentlichen benötigen Sie jedoch nichts, als nur den zu testenden Code-Block in einer eigenen Zeile auszuführen - pytest wird trotzdem fehlschlagen, sobald dieser Block einen Fehler auslöst.

+0

Ich wünschte, das wäre in py.test eingebaut; es würde Tests in einigen Fällen viel besser lesbar machen. Besonders in Verbindung mit '@ pytest.mark.parametrize'. – Arel

Verwandte Themen