8 Stimmen

Unkritische Unittest-Fehler

Ich verwende Pythons eingebaute unittest Modul und ich möchte ein paar Tests schreiben, die nicht kritisch sind.

Ich meine, wenn mein Programm solche Tests besteht, ist das großartig! Wenn es aber nicht besteht, ist das nicht wirklich ein Problem, das Programm wird trotzdem funktionieren.

Mein Programm soll zum Beispiel mit einem benutzerdefinierten Typ "A" funktionieren. Wenn es mit "A" nicht funktioniert, dann ist es kaputt. Der Einfachheit halber sollte das meiste jedoch auch mit einem anderen Typ "B" funktionieren, aber das ist nicht zwingend. Wenn es mit "B" nicht funktioniert, dann ist es nicht kaputt (weil es immer noch mit "A" funktioniert, was sein Hauptzweck ist). Wenn es mit "B" nicht funktioniert, ist das nicht kritisch, ich verpasse dann nur eine "Bonusfunktion", die ich haben könnte.

Ein weiteres (hypothetisches) Beispiel ist das Schreiben einer OCR. Der Algorithmus sollte die meisten Bilder aus den Tests erkennen, aber es ist in Ordnung, wenn einige von ihnen nicht erkannt werden. (und nein, ich schreibe keine OCR)

Gibt es eine Möglichkeit, nicht-kritische Tests in Unittest (oder einem anderen Test-Framework) zu schreiben?

8voto

Paul McMillan Punkte 19166

In der Praxis würde ich in diesem Fall wahrscheinlich print-Anweisungen verwenden, um einen Fehler anzuzeigen. Eine korrektere Lösung ist die Verwendung von Warnungen:

http://docs.python.org/library/warnings.html

Sie können jedoch die Protokollierungsfunktion nutzen, um eine detailliertere Aufzeichnung Ihrer Testergebnisse zu erstellen (z. B. können Sie festlegen, dass bei Fehlern der Klasse "B" Warnungen in die Protokolle geschrieben werden).

http://docs.python.org/library/logging.html

Editar:

Die Art und Weise, wie wir dies in Django handhaben, ist, dass wir einige Tests haben, von denen wir erwarten, dass sie fehlschlagen, und andere, die wir je nach Umgebung überspringen. Da wir im Allgemeinen vorhersagen können, ob ein Test fehlschlagen oder erfolgreich sein MUSS (d.h. wenn wir ein bestimmtes Modul nicht importieren können, hat das System es nicht, und der Test wird nicht funktionieren), können wir fehlende Tests intelligent überspringen. Das bedeutet, dass wir immer noch jeden Test ausführen, der bestehen wird, und keine Tests haben, die "vielleicht" bestehen. Unit-Tests sind am nützlichsten, wenn sie vorhersehbar sind, und wenn man in der Lage ist zu erkennen, ob ein Test erfolgreich sein MUSS oder nicht, bevor man ihn ausführt, ist dies möglich.

4voto

Asserts in Unit-Tests sind binär: Sie funktionieren oder sie scheitern, es gibt keinen Zwischenstand.

Um diese "unkritischen" Tests zu erstellen, sollten Sie daher keine Assertions verwenden, wenn Sie nicht wollen, dass die Tests fehlschlagen. Sie sollten dies sorgfältig tun, um die "Nützlichkeit" des Tests nicht zu gefährden.

Mein Rat zu Ihrem OCR-Beispiel ist, dass Sie etwas verwenden, um die Erfolgsrate in Ihrem Testcode aufzuzeichnen und dann eine Behauptung wie zu erstellen: "assert success_rate > 8.5", und das sollte den gewünschten Effekt erzielen.

4voto

Denilson Sá Maia Punkte 43844

Vielen Dank für die tollen Antworten. Nicht nur eine Antwort war wirklich vollständig, deshalb schreibe ich hier eine Kombination aus allen Antworten, die mir geholfen haben . Wenn Ihnen diese Antwort gefällt, stimmen Sie bitte für die Personen, die dafür verantwortlich sind.

Schlussfolgerungen

Einheitstests (oder zumindest Einheitstests in unittest Modul) sind binär. Als Guilherme Chapiewski sagt : Sie werden funktionieren oder scheitern, es gibt keine Zwischenlösung.

Daraus schließe ich, dass Unit-Tests nicht gerade das richtige Werkzeug für diese Aufgabe sind. Es scheint, dass Unit-Tests sich mehr um Folgendes kümmern "Damit alles funktioniert, wird kein Fehler erwartet" und deshalb kann ich keine nicht-binären Tests machen (oder es ist nicht einfach).

Unit-Tests scheinen also nicht das richtige Werkzeug zu sein, wenn ich versuche, einen Algorithmus oder eine Implementierung zu verbessern, denn Unit-Tests können mir nicht sagen, inwieweit eine Version im Vergleich zur anderen besser ist (vorausgesetzt, beide sind korrekt implementiert, dann bestehen beide alle Unit-Tests).

Meine endgültige Lösung

Meine endgültige Lösung basiert auf ryber's Idee und der Code in wcoenen Antwort . Ich bin im Grunde erweitern die Standard TextTestRunner und weniger ausführlich zu gestalten. Dann ruft mein Hauptcode zwei Testanzüge auf: den kritischen, der den Standard TextTestRunner und die unkritische, mit meiner eigenen, weniger ausführlichen Version.

class _TerseTextTestResult(unittest._TextTestResult):
    def printErrorList(self, flavour, errors):
        for test, err in errors:
            #self.stream.writeln(self.separator1)
            self.stream.writeln("%s: %s" % (flavour,self.getDescription(test)))
            #self.stream.writeln(self.separator2)
            #self.stream.writeln("%s" % err)

class TerseTextTestRunner(unittest.TextTestRunner):
    def _makeResult(self):
        return _TerseTextTestResult(self.stream, self.descriptions, self.verbosity)

if __name__ == '__main__':
    sys.stderr.write("Running non-critical tests:\n")
    non_critical_suite = unittest.TestLoader().loadTestsFromTestCase(TestSomethingNonCritical)
    TerseTextTestRunner(verbosity=1).run(non_critical_suite)

    sys.stderr.write("\n")

    sys.stderr.write("Running CRITICAL tests:\n")
    suite = unittest.TestLoader().loadTestsFromTestCase(TestEverythingImportant)
    unittest.TextTestRunner(verbosity=1).run(suite)

Mögliche Verbesserungen

Es sollte dennoch nützlich sein, zu wissen, ob es ein Test-Framework mit nicht-binären Tests gibt, wie Kathy Van Stone schlug vor . Wahrscheinlich werde ich es für dieses einfache persönliche Projekt nicht verwenden, aber es könnte bei zukünftigen Projekten nützlich sein.

3voto

ryber Punkte 4457

Ich bin mir nicht ganz sicher, wie Unittest funktioniert, aber die meisten Unit-Test-Frameworks haben so etwas wie Kategorien. Ich nehme an, man könnte solche Tests einfach kategorisieren, sie zum Ignorieren markieren und sie dann nur ausführen, wenn man an ihnen interessiert ist. Aber ich weiß aus Erfahrung, dass ignorierte Tests sehr schnell zu...eben jenen ignorierten Tests werden, die niemand jemals ausführt und daher eine Verschwendung von Zeit und Energie sind, sie zu schreiben.

Mein Rat ist, Ihre App zu tun oder nicht zu tun, es gibt keinen Versuch.

3voto

Wim Coenen Punkte 64891

Desde unittest Dokumentation, die Sie verlinken:

Anstelle von unittest.main() gibt es andere Möglichkeiten, die Tests mit einer feinerer Kontrolle, weniger knappen Ausgabe und ohne die Notwendigkeit, die Tests von der Kommandozeile aus. Zum Beispiel, können die letzten beiden Zeilen ersetzt werden durch:

suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
unittest.TextTestRunner(verbosity=2).run(suite)

In Ihrem Fall können Sie eine separate TestSuite Instanzen für die kritischen und unkritischen Tests. Sie können mit einem Befehlszeilenargument steuern, welche Suite an den Test Runner übergeben wird. Testsuiten können auch andere Testsuiten enthalten, so dass Sie große Hierarchien erstellen können, wenn Sie möchten.

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