1230 Stimmen

Wie testet man, dass eine Python-Funktion eine Ausnahme auslöst?

Wie kann man einen Unittest schreiben, der nur dann fehlschlägt, wenn eine Funktion keine erwartete Ausnahme auslöst?

1005voto

Moe Punkte 26523

Utilisez TestCase.assertRaises (oder TestCase.failUnlessRaises ) aus dem Unittest-Modul, zum Beispiel:

import mymod

class MyTestCase(unittest.TestCase):
    def test1(self):
        self.assertRaises(SomeCoolException, mymod.myfunc)

26 Stimmen

Gibt es eine Möglichkeit, das Gegenteil davon zu tun? Zum Beispiel, dass die Funktion nur dann fehlschlägt, wenn sie die Ausnahme auslöst?

157 Stimmen

Beachten Sie, dass die Übergabe von Argumenten an myfunc müssen Sie sie als Argumente zum assertRaises-Aufruf hinzufügen. Siehe die Antwort von Daryl Spitzer.

2 Stimmen

Gibt es eine Möglichkeit, mehrere Ausnahmetypen zuzulassen?

696voto

Art Punkte 22351

Seit Python 2.7 können Sie den Kontext-Manager verwenden, um an das tatsächliche Exception-Objekt zu gelangen, das ausgelöst wurde:

import unittest

def broken_function():
    raise Exception('This is broken')

class MyTestCase(unittest.TestCase):
    def test(self):
        with self.assertRaises(Exception) as context:
            broken_function()

        self.assertTrue('This is broken' in context.exception)

if __name__ == '__main__':
    unittest.main()

http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises


En Python 3.5 müssen Sie einpacken context.exception en str , sonst erhalten Sie eine TypeError

self.assertTrue('This is broken' in str(context.exception))

8 Stimmen

Ich verwende Python 2.7.10, und das oben genannte funktioniert nicht; context.exception gibt die Nachricht nicht an; es ist ein Typ.

10 Stimmen

Auch in Python 2.7 (zumindest in meiner 2.7.6) ist die Verwendung von import unittest2 müssen Sie Folgendes verwenden str() d.h. self.assertTrue('This is broken' in str(context.exception)) .

4 Stimmen

Zwei Dinge: 1. Sie können assertIn anstelle von assertTrue verwenden. Z.B. self.assertIn('This is broken', context.exception) 2. In meinem Fall, mit 2.7.10, scheint context.exception ein Array von Zeichen zu sein. Die Verwendung von str funktioniert nicht. Am Ende habe ich dies getan: ''.join(kontext.ausnahme) Also, zusammengesetzt: self.assertIn('Dies ist kaputt', ''.join(kontext.ausnahme))

530voto

Daryl Spitzer Punkte 131841

Der Code in meiner vorherigen Antwort kann vereinfacht werden zu:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction)

Und wenn eine Funktion Argumente benötigt, übergeben Sie diese einfach wie folgt an assertRaises:

def test_afunction_throws_exception(self):
    self.assertRaises(ExpectedException, afunction, arg1, arg2)

75 Stimmen

Der zweite Ausschnitt darüber, was zu tun ist, wenn das Argument übergangen wird, war wirklich hilfreich.

2 Stimmen

Ich benutze 2.7.15 . Wenn afunction en self.assertRaises(ExpectedException, afunction, arg1, arg2) ist der Klasseninitialisierer, Sie müssen self als erstes Argument z.B., self.assertRaises(ExpectedException, Class, self, arg1, arg2)

1 Stimmen

Es funktioniert auch, wenn arg vom Typ parameter=value sein muss, wie: self.assertRaises(ExpectedException, afunction, arg1=val1)

176voto

Wie testet man, dass eine Python-Funktion eine Ausnahme auslöst?

Wie kann man einen Test schreiben, der nur dann fehlschlägt, wenn eine Funktion keine eine erwartete Ausnahme auslöst?

Kurze Antwort:

Verwenden Sie die self.assertRaises Methode als Kontextmanager:

    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'

Demonstration

Der Best-Practice-Ansatz lässt sich recht einfach in einer Python-Shell demonstrieren.

El unittest Bibliothek

In Python 2.7 oder 3:

import unittest

In Python 2.6 können Sie einen Backport der 2.7er Version installieren unittest Bibliothek, genannt ungetestet2 und benennen Sie es einfach als unittest :

import unittest2 as unittest

Beispieltests

Fügen Sie nun in Ihrer Python-Shell den folgenden Test der Typsicherheit von Python ein:

class MyTestCase(unittest.TestCase):
    def test_1_cannot_add_int_and_str(self):
        with self.assertRaises(TypeError):
            1 + '1'
    def test_2_cannot_add_int_and_str(self):
        import operator
        self.assertRaises(TypeError, operator.add, 1, '1')

Test eins verwendet assertRaises als Kontextmanager, der sicherstellt, dass der Fehler ordnungsgemäß abgefangen und bereinigt wird, während er aufgezeichnet wird.

Wir könnten es auch so schreiben ohne den Kontextmanager, siehe Test zwei. Das erste Argument ist der Fehlertyp, den Sie erwarten, das zweite Argument ist die Funktion, die Sie testen, und die übrigen Args und Keyword-Args werden an diese Funktion übergeben.

Ich denke, es ist viel einfacher, lesbarer und wartbarer, einfach den Kontextmanager zu verwenden.

Durchführung der Tests

So führen Sie die Tests durch:

unittest.main(exit=False)

In Python 2.6 werden Sie wahrscheinlich benötigen Folgendes :

unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))

Und Ihr Terminal sollte folgendes ausgeben:

..
----------------------------------------------------------------------
Ran 2 tests in 0.007s

OK
<unittest2.runner.TextTestResult run=2 errors=0 failures=0>

Und wir sehen, dass, wie erwartet, der Versuch, eine 1 y un '1' führen zu einer TypeError .


Wenn Sie eine ausführlichere Ausgabe wünschen, versuchen Sie dies:

unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))

72voto

Daryl Spitzer Punkte 131841

Ihr Code sollte diesem Muster folgen (dies ist ein Test im Stil eines Unittest-Moduls):

def test_afunction_throws_exception(self):
    try:
        afunction()
    except ExpectedException:
        pass
    except Exception:
       self.fail('unexpected exception raised')
    else:
       self.fail('ExpectedException not raised')

Unter Python < 2.7 ist dieses Konstrukt nützlich, um auf bestimmte Werte in der erwarteten Ausnahme zu prüfen. Die Unittest-Funktion assertRaises prüft nur, ob eine Ausnahme ausgelöst wurde.

3 Stimmen

Und die Methode self.fail benötigt nur ein Argument

6 Stimmen

Dies scheint zu kompliziert, um zu testen, ob eine Funktion eine Ausnahme auslöst. Da jede andere Ausnahme als diese den Test fehlschlagen lässt und das Nicht-Auslösen einer Ausnahme den Test fehlschlagen lässt, scheint es, als ob der einzige Unterschied darin besteht, dass Sie eine andere Ausnahme erhalten, wenn Sie assertRaises erhalten Sie einen ERROR statt eines FAIL.

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