2017-02-06 6 views
4

Die Python 2.7 unittest docs sagen:Verwenden Sie eine benutzerdefinierte Fehlermeldung für `assertRaises()` in Python?

Alle assert Methoden (außer assertRaises(), assertRaisesRegexp()) akzeptieren ein msg Argument, dass, falls angegeben, da die Fehlermeldung bei einem Fehler verwendet

... aber was ist, wenn ich Möchten Sie die Fehlermeldung für assertRaises() oder assertRaisesRegexp() angeben?

Anwendungsfall: wenn verschiedene Werte in einer Schleife zu testen, wenn man versagt würde Ich mag wissen, was man:

NON_INTEGERS = [0.21, 1.5, 23.462, math.pi] 

class FactorizerTestCase(unittest.TestCase): 
    def test_exception_raised_for_non_integers(self): 
     for value in NON_INTEGERS: 
      with self.assertRaises(ValueError): 
       factorize(value) 

Wenn eine dieser ausfällt, erhalte ich:

AssertionError: ValueError not raised 

das ist nicht sehr hilfreich für mich, um herauszufinden, welche fehlgeschlagen ... wenn ich nur ein msg= Argument wie ich mit assertEqual() usw. liefern könnte!

(Ich könnte natürlich diese brechen in separaten Testfunktionen - aber vielleicht gibt es viele Werte, die ich testen wollen, oder es erfordert einige langsame/teure Einrichtung, oder es ist Teil einer längeren Funktionstest)

würde ich es lieben, wenn ich könnte leicht es so etwas wie Bericht:

AssertionError: ValueError not raised for input 23.462 

- aber es ist auch nicht kritisch genug, was zu rechtfertigen Neuimplementierung/Verlängerung assertRaises() und das Hinzufügen einer Last mehr Code meine Tests. (! Aber Hacky)

Antwort

2

1. Einfachste Weg, dies zu tun, die ich gefunden habe ist:

AssertionError: ValueError for 23.462 not raised 

Hinweis: diese nur Werke:

for value in NON_INTEGERS: 
    with self.assertRaises(ValueError) as cm: 
     cm.expected.__name__ = 'ValueError for {}'.format(value) # custom failure msg 
     factorize(value) 

, die diese bei einem Fehler berichten bei Verwendung der with … Syntax.

Es funktioniert, weil die assertRaises() context manager dies intern tut:

exc_name = self.expected.__name__ 
… 
raise self.failureException(
    "{0} not raised".format(exc_name)) 

so flockig sein könnte, wenn die Umsetzung ändert, obwohl die PY3 Quelle ähnlich genug ist, dass sie sollte es auch funktionieren (kann aber nicht sagen, Ich habe es versucht).

2. einfachste Weg ohne über die Umsetzung angewiesen ist, den Fehler zu fangen und wieder heben sie mit einer verbesserten Nachricht:

for value in NON_INTEGERS: 
    try: 
     with self.assertRaises(ValueError) as cm: 
      factorize(value) 
    except AssertionError as e: 
     raise self.failureException('{} for {}'.format(e.message, value)), sys.exc_info()[2] 

Das sys.exc_info()[2] Bit ist der Original-Stacktrace wieder zu verwenden, aber dies Syntax ist Py2 nur. This answer erklärt, wie man das für Py3 macht (und diese Lösung inspirierte).

Aber das macht bereits den Test schwer lesbar, also bevorzuge ich die erste Option.

Die 'richtige' Lösung würde schreiben eine aufgewickelte Version von beiden assertRaises AND der _AssertRaisesContext Klasse, die klingt wie Overkill, wenn Sie nur einige Protokollierung werfen könnte, wenn Sie einen Fehler erhalten.

0

Sie könnten auch mit self.fail Rückfall, die ärgerlich fühlt, sieht aber ein bisschen weniger hacky Ich denke

for value in NON_INTEGERS: 
    with self.assertRaises(ValueError) as cm: 
     factorize(value) 
     self.fail('ValueError not raised for {}'.format(value)) 
Verwandte Themen