Wie kann man einen Test von den Ergebnissen eines anderen Tests abhängig machen?

13

Angenommen, es gibt eine Utility-Klasse, die einige häufig verwendete statische Methoden enthält, die von vielen anderen Klassen überall in Ihrem Code verwendet werden.

Wie würden Sie Ihre Komponententests für die Verbraucher des Versorgungsunternehmens auslegen, damit deren Tests fehlschlagen, wenn einer der Versorgungstests nicht bestanden wird? Können Sie das tun oder müssen Sie selbst prüfen, ob die Tests der Utility-Klasse alle grün sind?

Zum Beispiel habe ich ein Message-Splitter-Dienstprogramm, das von einem Message-Parser verwendet wird (oder vielmehr dessen Ausgabe). Ich möchte sicherstellen, dass der Nachrichtensplitter ordnungsgemäß funktioniert, bevor der Nachrichtenparser getestet wird.

Ich habe Tests für beide geschrieben, aber gibt es eine Möglichkeit, sie zu verknüpfen und einen Test vom Ergebnis eines anderen Tests abhängig zu machen?

Ich konnte kein passendes Tag dafür finden, verwende aber die Unit-Test-Engine von Visual Studio.

t3chb0t
quelle
1
Ich verstehe, dass der Parser nicht richtig funktioniert, wenn das Dienstprogramm fehlschlägt. Wenn Sie jedoch Ihre Tests ausführen, werden Sie feststellen, dass die Utility-Tests fehlschlagen. Warum sollen auch andere Tests fehlschlagen?
Eugen Martynov
1
Ich habe noch nie von jemandem gehört, der das will. Was versuchst du zu erreichen?
Esben Skov Pedersen
Ich verwende einige der Dienstprogrammfunktionen, um Daten für die Parser-Tests vorzubereiten, daher möchte ich unbedingt sicherstellen, dass das Dienstprogramm ordnungsgemäß funktioniert, bevor ich etwas anderes teste.
t3chb0t
3
@ t3chb0t Wenn Sie sicherstellen möchten, dass Ihr Dienstprogramm funktioniert, müssen Sie Komponententests schreiben, um Ihr Dienstprogramm zu überprüfen. Unit-Tests sollten atomar sein. Sie möchten immer nur, dass sie eine einzelne Komponente testen.
maple_shaft

Antworten:

11

Es macht keinen Sinn sicherzustellen, dass jeder Defekt in Ihrem System genau einen Test auslöst.

Eine Testsuite hat eine Aufgabe: Sicherstellen, dass keine bekannten Fehler vorliegen. Wenn ein Defekt vorliegt, spielt es keine Rolle , ob ein Test fehlschlägt oder 10. Wenn Sie Ihre Testsuite Fehler gewöhnen, wenn Sie zu messen versuchen , wie „schlecht“ Ihr Programm ist durch Zählen der vorgeschriebenen Prüfungen nicht, du bist nicht Regressionstests richtig anwenden. Die Testsuite sollte alle Tests bestehen, bevor Sie Code veröffentlichen.

Der einzig gültige Grund für das Überspringen von Tests besteht darin, dass sie unvollständige Funktionen testen und übermäßig viel Zeit in Anspruch nehmen, die Sie für die Implementierung des zu testenden Objekts besser einsetzen können. (Dies ist nur dann ein Problem, wenn Sie keine strikte testgetriebene Entwicklung praktizieren, aber es ist schließlich eine gültige Wahl.)

Versuchen Sie ansonsten nicht, Ihre Testsuite zu einem Indikator zu machen, der Ihnen genau sagt, was nicht stimmt. Es wird niemals genau sein und es sollte auch nicht so sein. Es soll dich davor schützen, zweimal den gleichen Fehler zu machen, das ist alles.

Kilian Foth
quelle
8

Es hängt von Ihrem Werkzeug ab, aber Sie können (und sollten) wahrscheinlich nicht

In einigen Unit-Testing-Frameworks ( z. B. PHPUnit ) können Sie Tests verketten, sodass ein fehlgeschlagener Test auf einer Ebene keine anderen Tests ausführt. Ich bezweifle jedoch, dass dies Ihr Problem für diese Situation beheben wird.

Das Nichtzulassen einer garantierten Testauftragsausführung zwingt dazu, Tests voneinander zu trennen, und wird im Allgemeinen als eine gute Sache angesehen. Stellen Sie sich vor, was passieren würde, wenn die Tests nicht nur von selbst ausgeführt würden, sondern auch Daten für andere Tests liefern würden, an denen sie arbeiten könnten ...

Sie können diese Dienstprogrammmethoden in einer separaten Lösung oder Testkategorie ablegen. Stellen Sie sicher, dass sie in Ihrem Testläufer optisch hervorstechen oder dass diese Kategorie zuerst ausgeführt wird und keine anderen Tests ausführt, wenn die Tests in dieser Kategorie fehlschlagen *. Wenn einer dieser Tests fehlschlägt, wird der Fehler wahrscheinlich über alle Tests hinweg auftreten, und Sie sollten sicherstellen, dass jeder, der die Tests ausführt, zunächst diese fehlgeschlagenen Tests korrigiert. Gleiches gilt für Unit-Tests und Integrationstests. Wenn ein Unittest fehlschlägt, wird er in den Integrationstests kaskadieren und allerlei Chaos verursachen. Jeder weiß, dass Sie, wenn Unit- UND Integrationstests fehlschlagen, zunächst die Unittests überprüfen müssen ...

* Mit einem automatisierten Build- oder Testskript können Sie diese Kategorie zuerst ausführen, das Ergebnis überprüfen und die anderen Tests nur ausführen, wenn diese erste Testreihe erfolgreich ist.

JDT
quelle
5

Versuchen Sie, Ihren Komponententest atomar zu halten. Denken Sie daran, dass automatisierter Testcode ebenfalls Teil Ihrer Codebasis ist, sich aber selbst nicht im Test befindet. Halten Sie ihn daher so einfach und offensichtlich wie möglich.

Um Ihre Frage direkter zu beantworten, gibt es keine Garantie für die Ausführungsreihenfolge der Tests, so dass auch nicht garantiert werden kann, dass Ihr Utility-Test erfolgreich ist, bevor Ihre anderen Tests ausgeführt werden. Es gibt also keine garantierte Möglichkeit, das zu erreichen, was Sie möchten, während Sie für alle Ihre Tests eine einzige Testsuite haben.

Sie können die Dienstprogramme in ihre eigene Lösung verschieben und einen Verweis auf die resultierende DLL in Ihrem aktuellen Projekt hinzufügen.

Thorsal
quelle
4

In einer Zusammenfassung möchten Sie keine Werkzeuge / Techniken verwenden, um andere Dinge als die zu tun, für die sie bestimmt sind.

Was Sie versuchen, klingt nach einem Problem, das mit einer CI-Praxis (Continuous Integration) leicht gelöst werden kann.

Auf diese Weise können Sie Ihre Tests wie bereits vorgeschlagen atomar halten und das CI sich um die Überprüfung Ihrer Tests kümmern.

Wenn ein Test fehlschlägt, können Sie ihn so einstellen, dass Ihr Code nicht veröffentlicht wird.

AvetisG
quelle
4

Ich habe die Angewohnheit, immer zu versuchen, Code auf Anwendungsebene von Code auf Framework-Ebene zu unterscheiden. Daher bin ich auf das Problem gestoßen, das Sie häufig beschreiben: Normalerweise möchten Sie, dass der gesamte Code auf Framework-Ebene getestet wird, bevor Code auf Anwendungsebene getestet wird . Auch innerhalb von Code auf Framework-Ebene gibt es in der Regel einige grundlegende Framework-Module, die von allen anderen Framework-Modulen verwendet werden, und wenn etwas in den Grundlagen versagt, macht es keinen Sinn, etwas anderes zu testen.

Leider neigen die Anbieter von Test-Frameworks dazu, eine eher starre Vorstellung davon zu haben, wie ihre Kreationen verwendet werden sollen, und schützen diese Ideen eher, während die Leute, die ihre Frameworks verwenden, die beabsichtigte Verwendung eher akzeptieren, ohne zu hinterfragen. Das ist problematisch, weil es Experimente und Innovationen behindert. Ich kenne nicht alle anderen, aber ich würde es vorziehen, die Freiheit zu haben, zu versuchen, etwas auf seltsame Weise zu tun, und selbst zu sehen, ob die Ergebnisse besser oder schlechter sind als der etablierte Weg, anstatt nicht die Freiheit zu haben Mach die Dinge in erster Linie so, wie ich es will.

Meiner Meinung nach wären Testabhängigkeiten eine großartige Sache, und stattdessen wäre die Möglichkeit, die Reihenfolge festzulegen, in der die Tests ausgeführt werden, die nächstbeste.

Die einzige Möglichkeit, das Problem der Testreihenfolge zu lösen, besteht in der sorgfältigen Benennung, um die Tendenz von Testframeworks auszunutzen, Tests in alphabetischer Reihenfolge auszuführen.

Ich weiß nicht, wie dies in Visual Studio funktioniert, da ich noch nichts mit umfangreichen Tests mit C # zu tun habe, aber auf der Java-Seite der Welt funktioniert es wie folgt: Unter dem Quellordner eines Projekts haben wir normalerweise zwei Unterordner, eine mit dem Namen "main", der den Produktionscode enthält, und eine mit dem Namen "test", der den Testcode enthält. Unter "main" haben wir eine Ordnerhierarchie, die genau der Pakethierarchie unseres Quellcodes entspricht. Java-Pakete entsprechen in etwa C # -Namensräumen. In C # müssen Sie die Ordnerhierarchie nicht an die Namespace-Hierarchie anpassen, es wird jedoch empfohlen, dies zu tun.

Normalerweise spiegeln die Benutzer in der Java-Welt im Ordner "test" die Ordnerhierarchie im Ordner "main" wider, sodass sich jeder Test in genau demselben Paket befindet wie die Klasse, die er testet. Das Grundprinzip dahinter ist, dass die Testklasse häufig auf paketprivate Mitglieder der zu testenden Klasse zugreifen muss, sodass sich die Testklasse im selben Paket wie die zu testende Klasse befinden muss. Auf der C # -Seite der Welt gibt es keine Sichtbarkeit auf Namespaces, daher gibt es keinen Grund, die Ordnerhierarchien zu spiegeln, aber ich denke, dass C # -Programmierer bei der Strukturierung ihrer Ordner mehr oder weniger der gleichen Disziplin folgen.

Auf jeden Fall finde ich die ganze Idee, den Testklassen den Zugriff auf paketlokale Mitglieder der zu testenden Klassen zu ermöglichen, falsch, weil ich dazu neige, Schnittstellen und keine Implementierungen zu testen. Die Ordnerhierarchie meiner Tests muss also nicht die Ordnerhierarchie meines Produktionscodes widerspiegeln.

Also, was ich tue, ist, dass ich die Ordner (dh die Pakete) meiner Tests wie folgt benenne:

t001_SomeSubsystem
t002_SomeOtherSubsystem
t003_AndYetAnotherSubsystem
...

Dies garantiert, dass alle Tests für "SomeSubsystem" vor allen Tests für "SomeOtherSubsystem" ausgeführt werden, die wiederum alle vor allen Tests für "AndYetAnotherSubsystem" usw. ausgeführt werden.

Innerhalb eines Ordners werden einzelne Testdateien wie folgt benannt:

T001_ThisTest.java
T002_ThatTest.java
T003_TheOtherTest.java

Natürlich ist es sehr hilfreich, dass moderne IDEs über leistungsstarke Refactoring-Funktionen verfügen, mit denen Sie ganze Pakete (und alle Unterpakete sowie den gesamten Code, der auf sie verweist) mit nur wenigen Klicks und Tastatureingaben umbenennen können.

Mike Nakis
quelle
2
I don't know about everyone else, but I would prefer to have the freedom to try to do something in an odd way, and see for myself whether the results are better or worse++ Kumpel. Ich weiß nicht, dass ich die Lösung mag, aber ich mag die Haltung, die Sie dort gezeigt haben.
RubberDuck