Grundlegende Verzeichnisstruktur :
Ich habe versucht, den Testcode direkt neben dem zu testenden Code zu halten, buchstäblich im selben Verzeichnis mit einem etwas anderen Dateinamen als die Datei mit dem zu testenden Code. Bisher gefällt mir dieser Ansatz. Die Idee ist, dass Sie keine Zeit und Energie aufwenden müssen, um die Verzeichnisstruktur zwischen Ihrem Code und Ihrem Testcode synchron zu halten. Wenn Sie also den Namen des Verzeichnisses ändern, in dem sich der Code befindet, müssen Sie nicht auch den Verzeichnisnamen für den Testcode suchen und ändern. Dies führt auch dazu, dass Sie weniger Zeit damit verbringen, nach dem Testcode zu suchen, der zu einem Code gehört, da er sich direkt daneben befindet. Dies macht es sogar weniger mühsam, die Datei mit dem Testcode zu erstellen, da Sie nicht zuerst das Verzeichnis mit den Tests finden müssen. Erstellen Sie möglicherweise ein neues Verzeichnis, das mit dem Verzeichnis übereinstimmt, für das Sie Tests erstellen, und erstellen Sie dann die Testdatei. Sie erstellen einfach die Testdatei genau dort.
Ein großer Vorteil davon ist, dass die anderen Mitarbeiter (nicht Sie, weil Sie dies niemals tun würden) das Schreiben von Testcode zunächst weniger vermeiden, weil es einfach zu viel Arbeit ist. Selbst wenn sie Methoden zu vorhandenen Klassen hinzufügen, ist es weniger wahrscheinlich, dass sie keine Tests zum vorhandenen Testcode hinzufügen möchten, da das Auffinden des Testcodes nur wenig reibungslos funktioniert.
Ein Nachteil ist, dass es schwieriger ist, Ihren Produktionscode ohne die dazugehörigen Tests freizugeben. Wenn Sie strenge Namenskonventionen verwenden, ist dies möglicherweise dennoch möglich. Zum Beispiel habe ich ClassName.php, ClassNameUnitTest.php und ClassNameIntegrationTest.php verwendet. Wenn ich alle Unit-Tests ausführen möchte, gibt es eine Suite, die nach Dateien sucht, die auf UnitTest.php enden. Die Integrationstestsuite funktioniert ähnlich. Wenn ich wollte, könnte ich eine ähnliche Technik verwenden, um zu verhindern, dass die Tests für die Produktion freigegeben werden.
Ein weiterer Nachteil dieses Ansatzes besteht darin, dass bei der Suche nach tatsächlichem Code und nicht nach Testcode etwas mehr Aufwand erforderlich ist, um zwischen beiden zu unterscheiden. Aber ich denke, dass dies tatsächlich eine gute Sache ist, da es uns zwingt, den Schmerz der Realität zu spüren, dass Testcode auch Code ist, es seine eigenen Wartungskosten hinzufügt und genauso wichtig ein Teil des Codes ist wie alles andere, nicht nur irgendwo etwas abseits.
Eine Testklasse pro Klasse:
Dies ist für die meisten Programmierer alles andere als experimentell, aber für mich. Ich experimentiere damit, dass nur eine Testklasse pro Klasse getestet wird. In der Vergangenheit hatte ich für jede getestete Klasse ein ganzes Verzeichnis und dann mehrere Klassen in diesem Verzeichnis. Jede Testklasse richtete die zu testende Klasse auf eine bestimmte Art und Weise ein und ließ dann eine Reihe von Methoden mit jeweils einer anderen Behauptung erstellen. Aber dann bemerkte ich, dass bestimmte Bedingungen, in die ich diese Objekte bringen würde, Dinge mit anderen Bedingungen gemeinsam hatten, in die sie aus anderen Testklassen gerieten. Die Duplizierung ist zu umfangreich, daher habe ich angefangen, Abstraktionen zu erstellen, um sie zu entfernen. Der Testcode wurde sehr schwer zu verstehen und zu pflegen. Ich erkannte das, aber ich konnte keine Alternative sehen, die für mich Sinn machte. Nur eine Testklasse pro Klasse zu haben, schien nicht in der Lage zu sein, fast genug Situationen zu testen, ohne überwältigend zu werden, den gesamten Testcode in einer Testklasse zu haben. Jetzt habe ich eine andere Perspektive. Selbst wenn ich recht hatte, ist dies ein großer Dämpfer für andere Programmierer und mich, die die Tests schreiben und pflegen wollen. Jetzt experimentiere ich damit, mich zu zwingen, eine Testklasse pro getesteter Klasse zu haben. Wenn ich in dieser einen Testklasse auf zu viele Dinge stoße, um sie zu testen, experimentiere ich damit, dass dies ein Hinweis darauf ist, dass die getestete Klasse zu viel tut und in mehrere Klassen aufgeteilt werden sollte. Um Duplikate zu entfernen, versuche ich, mich so weit wie möglich an einfachere Abstraktionen zu halten, damit alles in einer lesbaren Testklasse vorhanden ist.
AKTUALISIEREN
Ich verwende und mag diesen Ansatz immer noch, aber ich habe eine sehr gute Technik gefunden, um die Menge an Testcode und die Menge an Duplikaten zu reduzieren. Es ist wichtig, wiederverwendbare Assertionsmethoden in die Testklasse selbst zu schreiben, die von den Testmethoden in dieser Klasse häufig verwendet werden. Es hilft mir, die richtigen Arten von Assertionsmethoden zu finden, wenn ich sie als interne DSLs betrachte (etwas, das Onkel Bob fördert, und tatsächlich fördert er das Erstellen interner DSLs). Manchmal können Sie dieses DSL-Konzept sogar noch weiter verfolgen (tatsächlich ein DSL erstellen), indem Sie einen Zeichenfolgenparameter akzeptieren, der einen einfachen Wert hat, der sich darauf bezieht, welche Art von Test Sie durchführen möchten. Zum Beispiel habe ich einmal eine wiederverwendbare Assertionsmethode erstellt, die einen $ left-, $ compareesAs- und einen $ right-Parameter akzeptiert.$this->assertCmp('a', '<', 'b')
.
Ehrlich gesagt kann ich diesen Punkt nicht genug betonen, es ist die gesamte Grundlage, um Schreibtests zu etwas Nachhaltigem zu machen (das Sie und die anderen Programmierer weiterhin tun möchten). Es macht es möglich, dass der Wert, den Tests hinzufügen, überwiegt, was sie wegnehmen. Der Punkt ist nicht, dass Sie genau diese Technik verwenden müssen, der Punkt ist, dass Sie eine Art wiederverwendbarer Abstraktionen verwenden müssen, mit denen Sie kurze und lesbare Tests schreiben können. Es mag so aussehen, als würde ich von der Frage abweichen, aber das bin ich wirklich nicht. Wenn Sie dies nicht tun, werden Sie schließlich in die Falle geraten, mehrere Testklassen pro getesteter Klasse erstellen zu müssen, und die Dinge brechen von dort aus wirklich zusammen.