Um sicherzustellen, dass die Fehlermeldungen von meinem Modul informativ sind, möchte ich alle von assertRaises () abgefangenen Fehlermeldungen sehen. Heute mache ich es für jede assertRaises (), aber da es viele davon im Testcode gibt, wird es sehr langweilig.
Wie kann ich die Fehlermeldungen für alle assertRaises () drucken? Ich habe die Dokumentation unter http://docs.python.org/library/unittest.html studiert, ohne herauszufinden, wie ich sie lösen kann. Kann ich die assertRaises () -Methode irgendwie monkeypatchen? Ich ziehe es vor, nicht alle assertRaises () -Zeilen im Testcode zu ändern, da ich den Testcode meistens standardmäßig verwende.
Ich denke, diese Frage bezieht sich auf Python unittest: Wie teste ich das Argument in einer Ausnahme?
So mache ich es heute. Zum Beispiel:
#!/usr/bin/env python
def fail():
raise ValueError('Misspellled errrorr messageee')
Und der Testcode:
#!/usr/bin/env python
import unittest
import failure
class TestFailureModule(unittest.TestCase):
def testFail(self):
self.assertRaises(ValueError, failure.fail)
if __name__ == '__main__':
unittest.main()
Um die Fehlermeldung zu überprüfen, ändere ich einfach den Fehlertyp in assertRaises () in beispielsweise IOError. Dann kann ich die Fehlermeldung sehen:
E
======================================================================
ERROR: testFail (__main__.TestFailureModule)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_failure.py", line 8, in testFail
self.assertRaises(IOError, failure.fail)
File "/usr/lib/python2.7/unittest/case.py", line 471, in assertRaises
callableObj(*args, **kwargs)
File "/home/jonas/Skrivbord/failure.py", line 4, in fail
raise ValueError('Misspellled errrorr messageee')
ValueError: Misspellled errrorr messageee
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (errors=1)
Irgendwelche Vorschläge? / Jonas
BEARBEITEN:
Mit den Hinweisen von Robert Rossney gelang es mir, das Problem zu lösen. Es ist nicht hauptsächlich für Rechtschreibfehler gedacht, sondern um sicherzustellen, dass die Fehlermeldungen für den Benutzer des Moduls wirklich aussagekräftig sind. Die normale Funktionalität von unittest (so verwende ich es meistens) wird erreicht, indem SHOW_ERROR_MESSAGES = False gesetzt wird.
Ich überschreibe einfach die assertRaises () -Methode, wie unten gezeigt. Es funktioniert wie Charme!
SHOW_ERROR_MESSAGES = True
class NonexistantError(Exception):
pass
class ExtendedTestCase(unittest.TestCase):
def assertRaises(self, excClass, callableObj, *args, **kwargs):
if SHOW_ERROR_MESSAGES:
excClass = NonexistantError
try:
unittest.TestCase.assertRaises(self, excClass, callableObj, *args, **kwargs)
except:
print '\n ' + repr(sys.exc_info()[1])
Ein Bruchteil der resultierenden Ausgabe:
testNotIntegerInput (__main__.TestCheckRegisteraddress) ...
TypeError('The registeraddress must be an integer. Given: 1.0',)
TypeError("The registeraddress must be an integer. Given: '1'",)
TypeError('The registeraddress must be an integer. Given: [1]',)
TypeError('The registeraddress must be an integer. Given: None',)
ok
testCorrectNumberOfBytes (__main__.TestCheckResponseNumberOfBytes) ... ok
testInconsistentLimits (__main__.TestCheckNumerical) ...
ValueError('The maxvalue must not be smaller than minvalue. Given: 45 and 47, respectively.',)
ValueError('The maxvalue must not be smaller than minvalue. Given: 45.0 and 47.0, respectively.',)
ok
testWrongValues (__main__.TestCheckRegisteraddress) ...
ValueError('The registeraddress is too small: -1, but minimum value is 0.',)
ValueError('The registeraddress is too large: 65536, but maximum value is 65535.',)
ok
testTooShortString (__main__.TestCheckResponseWriteData) ...
ValueError("The payload is too short: 2, but minimum value is 4. Given: '\\x00X'",)
ValueError("The payload is too short: 0, but minimum value is 4. Given: ''",)
ValueError("The writedata is too short: 1, but minimum value is 2. Given: 'X'",)
ValueError("The writedata is too short: 0, but minimum value is 2. Given: ''",)
ok
testKnownValues (__main__.TestCreateBitPattern) ... ok
testNotIntegerInput (__main__.TestCheckSlaveaddress) ...
TypeError('The slaveaddress must be an integer. Given: 1.0',)
TypeError("The slaveaddress must be an integer. Given: '1'",)
TypeError('The slaveaddress must be an integer. Given: [1]',)
TypeError('The slaveaddress must be an integer. Given: None',)
ok
quelle
try
und untersuchenexcept
?Antworten:
Out-of-the-Box
unittest
macht das nicht. Wenn Sie dies häufig tun möchten, können Sie Folgendes ausprobieren:class ExtendedTestCase(unittest.TestCase): def assertRaisesWithMessage(self, msg, func, *args, **kwargs): try: func(*args, **kwargs) self.assertFail() except Exception as inst: self.assertEqual(inst.message, msg)
Leiten Sie Ihre Unit-Test-Klassen von
ExtendedTestCase
stattunittest.TestCase
.Aber wirklich, wenn Sie nur über falsch geschriebene Fehlermeldungen besorgt sind und genug Bedenken haben, um Testfälle darum herum zu erstellen, sollten Sie Nachrichten nicht als Zeichenfolgenliterale einbinden. Sie sollten mit ihnen das tun, was Sie mit anderen wichtigen Zeichenfolgen tun: Definieren Sie sie als Konstanten in einem Modul, das Sie importieren, und dass jemand für das Korrekturlesen verantwortlich ist. Ein Entwickler, der Wörter in seinem Code falsch schreibt, schreibt sie auch in seinen Testfällen falsch.
quelle
inst.args[0]
stattdessen verwendeninst.message
, um diesen Code sowohl auf Python 2 als auch auf Python 3unittest
die sofort einsatzbereiten Funktionen sehr umfangreich sind.Ich habe einmal die beste Antwort von @Robert Rossney vorgezogen. Heutzutage bevorzuge ich die Verwendung von assertRaises als Kontextmanager (eine neue Funktion in unittest2) wie folgt:
with self.assertRaises(TypeError) as cm: failure.fail() self.assertEqual( 'The registeraddress must be an integer. Given: 1.0', str(cm.exception) )
quelle
Sie suchen nach assertRaisesRegex , das seit Python 3.2 verfügbar ist. Aus den Dokumenten:
self.assertRaisesRegex(ValueError, "invalid literal for.*XYZ'$", int, 'XYZ')
oder:
with self.assertRaisesRegex(ValueError, 'literal'): int('XYZ')
PS: Wenn Sie Python 2.7 verwenden, lautet der korrekte Methodenname
assertRaisesRegexp
.quelle
DeprecationWarning: Please use assertRaisesRegex instead
bei Verwendungwith self.assertRaisesRegexp( RuntimeError, '...regex...' )
Wenn Sie möchten, dass die Fehlermeldung genau mit etwas übereinstimmt:
with self.assertRaises(ValueError) as error: do_something() self.assertEqual(error.exception.message, 'error message')
quelle
str(error.exception)
anstelle vonerror.exception.message
aserror.exception
keinmessage
Attribut in meinem Fall verwenden.mkelley33 gibt eine gute Antwort, aber dieser Ansatz kann von einigen Code-Analyse-Tools wie Codacy als Problem erkannt werden . Das Problem ist, dass es nicht weiß,
assertRaises
dass es als Kontextmanager verwendet werden kann, und dass nicht alle Argumente an dieassertRaises
Methode übergeben werden .Also möchte ich Roberts Rossney-Antwort verbessern:
class TestCaseMixin(object): def assertRaisesWithMessage(self, exception_type, message, func, *args, **kwargs): try: func(*args, **kwargs) except exception_type as e: self.assertEqual(e.args[0], message) else: self.fail('"{0}" was expected to throw "{1}" exception' .format(func.__name__, exception_type.__name__))
Hauptunterschiede sind:
e.args[0]
ausführen (wir rufen auf, weil Fehler in Py3 keinmessage
Attribut haben).quelle
e.args[0]
, können Sie auch aufrufenstr(e)
.