Ich möchte einen Test schreiben, um festzustellen, dass unter bestimmten Umständen keine Exception ausgelöst wird.
Es ist einfach zu testen, ob eine Ausnahme ist erhöht ist ...
sInvalidPath=AlwaysSuppliesAnInvalidPath()
self.assertRaises(PathIsNotAValidOne, MyObject, sInvalidPath)
... aber wie kann man das Gegenteil machen?
So etwas habe ich, was ich suche ...
sValidPath=AlwaysSuppliesAValidPath()
self.assertNotRaises(PathIsNotAValidOne, MyObject, sValidPath)
def run_test(self):
try:
myFunc()
except ExceptionType:
self.fail("myFunc() raised ExceptionType unexpectedly!")
Hallo - Ich möchte einen Test schreiben, um festzustellen, dass unter bestimmten Umständen keine Exception ausgelöst wird.
Dies ist die Standardannahme - Ausnahmen werden nicht ausgelöst.
Wenn Sie nichts anderes sagen, wird dies bei jedem Test angenommen.
Sie müssen dafür keine Aussage machen.
Rufen Sie einfach die Funktion auf. Wenn eine Ausnahme ausgelöst wird, wird das Gerätetest-Framework dies als Fehler kennzeichnen. Sie möchten vielleicht einen Kommentar hinzufügen, z.
sValidPath=AlwaysSuppliesAValidPath()
# Check PathIsNotAValidOne not thrown
MyObject(sValidPath)
Ich bin das Originalposter und habe die obige Antwort von DGH akzeptiert, ohne sie zuvor im Code verwendet zu haben.
Als ich das Gerät einmal benutzt hatte, wurde mir klar, dass es ein wenig mehr nötig war, um das zu tun, was ich brauchte (um der DGH gerecht zu werden, sagte er/sie "oder etwas ähnliches"!).
Ich dachte, es lohnt sich, den Tweak hier zu veröffentlichen, um anderen zu helfen:
try:
a = Application("abcdef", "")
except pySourceAidExceptions.PathIsNotAValidOne:
pass
except:
self.assertTrue(False)
Was ich hier tun wollte, war sicherzustellen, dass bei einem Versuch, ein Application-Objekt mit einem zweiten Argument von Leerzeichen zu instantiieren, pySourceAidExceptions.PathIsNotAValidOne ausgelöst wird.
Ich glaube, dass der oben genannte Code (basierend auf der Antwort der DGH) dies tun wird.
Sie können assertNotRaises
definieren, indem Sie ca. 90% der ursprünglichen Implementierung von assertRaises
im Modul unittest
wiederverwenden. Bei diesem Ansatz erhalten Sie eine assertNotRaises
-Methode, die sich abgesehen von ihrer umgekehrten Fehlerbedingung mit assertRaises
identisch verhält.
Es stellt sich als überraschend einfach heraus, eine assertNotRaises
-Methode zu unittest.TestCase
hinzuzufügen (ich habe ungefähr viermal so lange gebraucht, um diese Antwort zu schreiben als der Code). Hier ist eine Live-Demo der assertNotRaises
-Methode in Aktion . Sie können einfach wie assertRaises
entweder ein callable und args an assertNotRaises
übergeben, oder Sie können es in einer with
-Anweisung verwenden. Die Live-Demo enthält Testfälle, die zeigen, dass assertNotRaises
wie beabsichtigt funktioniert.
Die Implementierung von assertRaises
in unittest
ist ziemlich kompliziert, aber mit ein wenig kluger Unterklassifizierung können Sie die Fehlerbedingung überschreiben und umkehren.
assertRaises
ist eine kurze Methode, die im Grunde nur eine Instanz der unittest.case._AssertRaisesContext
-Klasse erstellt und zurückgibt (siehe Definition im unittest.case
-Modul). Sie können Ihre eigene _AssertNotRaisesContext
-Klasse definieren, indem Sie _AssertRaisesContext
subclassing und die __exit__
-Methode überschreiben:
import traceback
from unittest.case import _AssertRaisesContext
class _AssertNotRaisesContext(_AssertRaisesContext):
def __exit__(self, exc_type, exc_value, tb):
if exc_type is not None:
self.exception = exc_value.with_traceback(None)
try:
exc_name = self.expected.__name__
except AttributeError:
exc_name = str(self.expected)
if self.obj_name:
self._raiseFailure("{} raised by {}".format(exc_name,
self.obj_name))
else:
self._raiseFailure("{} raised".format(exc_name))
else:
traceback.clear_frames(tb)
return True
Normalerweise definieren Sie Testfallklassen, indem Sie sie von TestCase
erben lassen. Wenn Sie stattdessen von einer Unterklasse erben, MyTestCase
:
class MyTestCase(unittest.TestCase):
def assertNotRaises(self, expected_exception, *args, **kwargs):
context = _AssertNotRaisesContext(expected_exception, self)
try:
return context.handle('assertNotRaises', args, kwargs)
finally:
context = None
für alle Ihre Testfälle steht jetzt die assertNotRaises
-Methode zur Verfügung.
Wenn Sie eine Exception-Klasse an assertRaises()
übergeben, wird ein Kontextmanager bereitgestellt. Dies kann die Lesbarkeit Ihrer Tests verbessern:
# raise exception if Application created with bad data
with self.assertRaises(pySourceAidExceptions.PathIsNotAValidOne):
application = Application("abcdef", "")
Auf diese Weise können Sie Fehlerfälle in Ihrem Code testen.
In diesem Fall testen Sie, dass PathIsNotAValidOne
ausgelöst wird, wenn Sie ungültige Parameter an den Anwendungskonstruktor übergeben.
Ich habe es für nützlich gefunden, unittest
wie folgt zu aktualisieren:
def assertMayRaise(self, exception, expr):
if exception is None:
try:
expr()
except:
info = sys.exc_info()
self.fail('%s raised' % repr(info[0]))
else:
self.assertRaises(exception, expr)
unittest.TestCase.assertMayRaise = assertMayRaise
Dies verdeutlicht die Absicht beim Testen auf das Fehlen einer Ausnahme:
self.assertMayRaise(None, does_not_raise)
Dies vereinfacht auch das Testen in einer Schleife, die ich oft mache:
# ValueError is raised only for op(x,x), op(y,y) and op(z,z).
for i,(a,b) in enumerate(itertools.product([x,y,z], [x,y,z])):
self.assertMayRaise(None if i%4 else ValueError, lambda: op(a, b))
def _assertNotRaises(self, exception, obj, attr):
try:
result = getattr(obj, attr)
if hasattr(result, '__call__'):
result()
except Exception as e:
if isinstance(e, exception):
raise AssertionError('{}.{} raises {}.'.format(obj, attr, exception))
könnte geändert werden, wenn Sie Parameter akzeptieren müssen.
nennen wie
self._assertNotRaises(IndexError, array, 'sort')
sie können es so versuchen. Versuchen: self.assertRaises (Keine, Funktion, Arg1, Arg2) außer: Pass Wenn Sie keinen Try-Block in den Try-Block einfügen, wird durch die Ausnahme 'AssertionError: None nicht ausgelöst' der Testfall fehlschlagen.