Antworten:
Wie Ihre Tests organisiert sind, ist im Vergleich zu der Wichtigkeit, sie überhaupt zu haben, eher unwichtig.
Das Wichtigste für eine gute Testsuite ist, dass sie alle Funktionen abdeckt. So stellen Sie sicher, dass Sie bei jedem Auftreten eines Regressionsfehlers sofort darauf aufmerksam werden. Es ist weniger wichtig, einen Test für jede Methode, einen Test für jede Eingabewertkombination einer Methode oder sogar einen Test für jeden möglichen Codepfad innerhalb dieser Methode zu schreiben. Ob diese Tests in wenigen oder vielen Testklassen organisiert werden, ist noch weniger wichtig: Eine Testsuite sollte immer vollständig erfolgreich sein, es spielt also keine Rolle, ob einer von drei oder zwei von siebzehn Tests fehlschlägt - beide sind falsch und müssen es sein Fest.
Natürlich ist Testcode auch Code, daher sollte er den normalen Best Practices für Wartbarkeit, Modularität usw. folgen. Dies muss jedoch davon abhängen, wie gut die Testsuite selbst gewartet werden kann, und nicht davon, in welchem Verhältnis die Testklassen zur Klassen, die sie testen. Beide Richtlinien, die Sie erwähnen, können Ihnen dabei helfen, sich zu erinnern, wo Sie Dinge finden, wenn Sie sie konsequent befolgen. Dabei ist jedoch die Konsistenz wichtiger als die Wahl der Richtlinie.
Zu Ihrer speziellen Frage, der JUnit-Konvention, gehört eine 1: 1-Entsprechung zwischen Ihren Anwendungsklassen ( Foo1.java
, Foo2.java
) und den JUnit-Testklassen ( Foo1Test.java
, Foo2Test.java
).
Trotzdem stimme ich voll und ganz Kilians Hervorhebung der Wichtigkeit des Geistes / der Ziele von Unit-Tests gegenüber möglichen Organisationsschemata zu. Wählen Sie einige Konventionen aus und halten Sie sich die meiste Zeit daran, während Sie vorsichtig Ausnahmen von Ihren Konventionen zulassen, wenn sie gerechtfertigt sind.
Ist es besser, für jede Methode eine eigene Klasse zu haben oder nur eine Testklasse für jede tatsächliche Klasse?
Wenn Sie separate Testklassen für Methoden einer Klasse schreiben müssen, haben Sie das falsche Design. Die Methoden sollten klein, leicht zu lesen, leicht zu testen und leicht zu ändern sein. Die Tests könnten etwas länger als der ursprüngliche Code sein, da Testdaten, Verspottungen usw. erstellt wurden, sollten aber nicht wesentlich länger sein. Wenn dies der Fall ist, ist Ihre getestete Klasse zu komplex und erfüllt mit Sicherheit mehr als eine Aufgabe (Prinzip der Einzelverantwortung ): Arbeiten Sie an Ihrem Design.
Ich denke, dass sowohl "eine Testklasse pro Methode" als auch "eine Testklasse pro Klasse" normalerweise zu extrem sind.
Im Allgemeinen möchten Sie eine Überprüfung pro Testmethode / Unit-Test durchführen. Dies können beispielsweise mehrere Aussagen sein, um zu überprüfen, ob ein list.isEmpty = true
und list.Length = 0
, also eine Testmethode / ein Komponententest pro Verhalten vorliegt.
Auf diese Weise können Sie leicht einen Namen für die Testmethode festlegen, der das Verhalten beschreibt. Sie möchten Testmethoden in einer Testklasse gruppieren. Wenn Sie also die lesen test classname.test method
, ist dies sinnvoll. Normalerweise haben diese einen gemeinsamen Setup-Code, der dann einfach in das Test-Setup / Fixture eingefügt werden kann. Abhängig von der zu testenden Klasse kann dies eine Testklasse für die gesamte Klasse und eine Testklasse für eine Methode sein. Aber normalerweise wird es irgendwo dazwischen sein.
Wie bei normalem Code möchten Sie, dass die Tests so gut wie möglich lesbar sind. Was mir hilft, ist die Befolgung des BDD-Stils für die Organisation des Testcodes. Eine Testklasse könnte das gegeben haben, es ist eingerichtet. Dann verwendet jede Testmethode in dieser Klasse die angegebene (oder einen Teil davon) und hat eine Wann- und eine Dann-Methode.
Stellen Sie sich die Unit-Tests auch als Dokumentation zur Verwendung der Funktionalität der zu testenden Klasse vor. Mit guten Komponententests können Sie die Tests lesen, um herauszufinden, wie die Funktionalität der gewünschten Klasse verwendet wird und welche Auswirkungen sie genau haben.
Wenn etwas kaputt geht und ein Komponententest fehlschlägt, möchten Sie, dass Sie so einfach wie möglich verstehen, was kaputt gegangen ist. Eine Aussage pro Test hilft hier sehr. Wenn ein Test mehrere Zusicherungen enthält, schlägt nur die erste fehl, und die Methode wird beendet. Sie wissen daher nicht, ob das in den folgenden Tests getestete Verhalten ebenfalls fehlerhaft ist, bis Sie das Problem behoben haben, bei dem die erste Zusicherung fehlgeschlagen ist. Mit einer Behauptung werden alle Ihre anderen Testmethoden noch ausgeführt und es ist viel schneller, die Tiefe des Fehlers zu verstehen.
Natürlich stimme ich Kilian Foth zu: In der Praxis können Sie sich glücklich schätzen, ein paar Unit-Tests für den Code zu haben, an dem Sie arbeiten. Und jeder kleine lokalisierte Test ist besser als gar kein Test, oder nur große Integrationstests, die auf dem Build-Server ausgeführt werden, nehmen viel Zeit in Anspruch und sind in der Regel nicht sehr lokalisiert (sie sagen Ihnen nicht schnell, wo der Fehler liegt - Sie muss noch ein wenig dran arbeiten).
Ich finde es richtig, dass jede Klasse ihre Testklasse hat. Die Idee ist, alle Unit-Tests, die sich auf die Zielklasse beziehen, in einer einzigen Testklasse zu zentralisieren. Dann wird zum Beispiel MyClass.java
seine Testklasse aufgerufen MyClassTest.java
.