Bei der Untersuchung der Best Practices für Unit-Tests zur Erstellung von Richtlinien für mein Unternehmen bin ich auf die Frage gestoßen, ob es besser oder nützlicher ist, Testgeräte (Testklassen) zu trennen oder alle Tests für eine einzelne Klasse in einer Datei zu speichern.
Fwiw, ich beziehe mich auf "Komponententests" in dem reinen Sinne, dass es sich um White-Box-Tests handelt, die auf eine einzelne Klasse abzielen, eine Aussage pro Test, alle Abhängigkeiten werden verspottet usw.
Ein Beispielszenario ist eine Klasse ("Dokument") mit zwei Methoden: CheckIn und CheckOut. Jede Methode implementiert verschiedene Regeln usw., die ihr Verhalten steuern. Nach der Regel "One-Assertion-per-Test" werden für jede Methode mehrere Tests durchgeführt. Ich kann entweder alle Tests in eine einzelne DocumentTests
Klasse mit Namen wie CheckInShouldThrowExceptionWhenUserIsUnauthorized
und einfügen CheckOutShouldThrowExceptionWhenUserIsUnauthorized
.
Oder ich könnte zwei separate Testklassen haben: CheckInShould
und CheckOutShould
. In diesem Fall würden meine Testnamen gekürzt, aber sie würden so organisiert, dass alle Tests für ein bestimmtes Verhalten (Methode) zusammen sind.
Ich bin mir sicher, dass es Vor- und Nachteile für beide Ansätze gibt, und frage mich, ob jemand mit mehreren Dateien den Weg gegangen ist, und wenn ja, warum? Oder, wenn Sie sich für den Single-File-Ansatz entschieden haben, warum ist er Ihrer Meinung nach besser?
quelle
testResponseContainsSuccessTrue()
,testResponseContainsMyData()
undtestResponseStatusCodeIsOk()
. Sie würden sie in einem einzigen habentestResponse()
die drei behauptet hat:assertEquals(200, response.status)
,assertEquals({"data": "mydata"}, response.data)
undassertEquals(true, response.success)
Antworten:
Es ist selten, aber manchmal ist es sinnvoll, mehrere Testklassen für eine bestimmte zu testende Klasse zu haben. Normalerweise würde ich dies tun, wenn verschiedene Setups erforderlich sind und für eine Teilmenge der Tests gemeinsam genutzt werden.
quelle
Ich kann keinen überzeugenden Grund dafür erkennen, warum Sie einen Test für eine einzelne Klasse in mehrere Testklassen aufteilen. Da die treibende Idee darin bestehen sollte, den Zusammenhalt auf Klassenebene aufrechtzuerhalten, sollten Sie dies auch auf Testebene anstreben. Nur ein paar zufällige Gründe:
quelle
Wenn Sie gezwungen sind, Komponententests für eine Klasse auf mehrere Dateien aufzuteilen, kann dies ein Hinweis darauf sein, dass die Klasse selbst schlecht konzipiert ist. Ich kann mir kein Szenario vorstellen, in dem es vorteilhafter wäre, die Komponententests für eine Klasse aufzuteilen, die dem Prinzip der Einzelverantwortung und anderen bewährten Programmiermethoden angemessen entspricht.
Darüber hinaus ist es akzeptabel, längere Methodennamen in Komponententests zu haben. Wenn Sie dies jedoch stören, können Sie die Namenskonvention für Komponententests jederzeit überdenken, um die Namen zu verkürzen.
quelle
Eines meiner Argumente gegen die Aufteilung der Tests in mehrere Klassen ist, dass es für andere Entwickler im Team (insbesondere diejenigen, die nicht so versiert sind) schwieriger wird, die vorhandenen Tests zu finden ( Gee, ich frage mich, ob es dafür bereits einen Test gibt) method? Ich frage mich, wo es sein würde? ) und auch, wo neue Tests abgelegt werden sollen ( ich schreibe einen Test für diese Methode in diese Klasse, bin mir aber nicht ganz sicher, ob ich sie in eine neue Datei oder in eine vorhandene Datei einfügen soll eine? )
Für den Fall, dass verschiedene Tests drastisch unterschiedliche Setups erfordern, habe ich gesehen, dass einige TDD-Anwender das "Fixture" oder das "Setup" in verschiedene Klassen / Dateien eingeteilt haben, aber nicht die Tests selbst.
quelle
Ich wünschte, ich könnte mich an den Link erinnern, in dem die von mir gewählte Technik zum ersten Mal demonstriert wurde. Im Wesentlichen erstelle ich für jede getestete Klasse eine einzelne abstrakte Klasse, die verschachtelte Test-Fixtures (Klassen) für jedes getestete Mitglied enthält. Dadurch wird die ursprünglich gewünschte Trennung erzielt, aber alle Tests werden für jeden Speicherort in derselben Datei gespeichert. Darüber hinaus wird ein Klassenname generiert, der eine einfache Gruppierung und Sortierung im Testrunner ermöglicht.
Hier ist ein Beispiel, wie dieser Ansatz auf mein ursprüngliches Szenario angewendet wird:
Dies führt dazu, dass die folgenden Tests in der Testliste angezeigt werden:
Wenn weitere Tests hinzugefügt werden, können diese einfach gruppiert und nach Klassennamen sortiert werden. Dadurch bleiben auch alle Tests für die zu testende Klasse zusammen aufgelistet.
Ein weiterer Vorteil dieses Ansatzes, den ich zu nutzen gelernt habe, ist die objektorientierte Struktur, die es mir ermöglicht, Code innerhalb der Start- und Bereinigungsmethoden der DocumentTests-Basisklasse zu definieren, der von allen verschachtelten Klassen sowie von jeder Klasse gemeinsam genutzt wird verschachtelte Klasse für die darin enthaltenen Tests.
quelle
Versuchen Sie für eine Minute anders herum zu denken.
Warum sollten Sie nur eine Testklasse pro Klasse haben? Machst du einen Klassentest oder einen Komponententest? Bist du überhaupt auf Klassen angewiesen ?
Ein Unit-Test soll ein bestimmtes Verhalten in einem bestimmten Kontext testen. Die Tatsache, dass Ihre Klasse bereits ein
CheckIn
Mittel hat, sollte es ein Verhalten geben, das es an erster Stelle benötigt.Wie würden Sie über diesen Pseudocode denken:
Jetzt testen Sie die
checkIn
Methode nicht direkt . Sie testen stattdessen ein Verhalten (das Sie zum Glück einchecken müssen;)). Wenn Sie es umgestaltenDocument
und in verschiedene Klassen aufteilen oder eine andere Klasse darin zusammenführen müssen, sind Ihre Testdateien immer noch kohärent. Sie sind immer noch sinnvoll, da Sie ändern beim Refactoring nie die Logik, sondern nur die Struktur.Eine Testdatei für eine Klasse macht es einfach schwieriger, sie bei Bedarf umzugestalten, und Tests sind auch in Bezug auf die Domäne / Logik des Codes selbst weniger sinnvoll.
quelle
Im Allgemeinen würde ich empfehlen, Tests als Test des Verhaltens der Klasse und nicht als Methode zu betrachten. Das heißt, einige Ihrer Tests müssen möglicherweise beide Methoden für die Klasse aufrufen, um das erwartete Verhalten zu testen.
Normalerweise beginne ich mit einer Unit-Test-Klasse pro Produktionsklasse, kann diese Unit-Test-Klasse jedoch aufgrund des von ihnen getesteten Verhaltens in mehrere Testklassen aufteilen. Mit anderen Worten würde ich empfehlen, die Testklasse nicht in CheckInShould und CheckOutShould aufzuteilen, sondern nach dem Verhalten des Prüflings aufzuteilen.
quelle
1. Überlegen Sie, was wahrscheinlich schief gehen wird
Während der ersten Entwicklung wissen Sie ziemlich genau, was Sie tun, und beide Lösungen funktionieren wahrscheinlich einwandfrei.
Interessanter wird es, wenn ein Test nach einer Änderung viel später fehlschlägt. Es gibt zwei Möglichkeiten:
CheckIn
(oderCheckOut
). Auch in diesem Fall sind sowohl die Einzeldatei- als auch die Doppeldateilösung in Ordnung.CheckIn
undCheckOut
(und möglicherweise ihre Tests) auf eine Weise geändert , die für jeden von ihnen Sinn macht, aber nicht für beide zusammen. Sie haben die Kohärenz des Paares gebrochen. In diesem Fall wird es schwieriger, das Problem zu verstehen, wenn die Tests auf zwei Dateien aufgeteilt werden.2. Überlegen Sie, wofür Tests verwendet werden
Tests dienen zwei Hauptzwecken:
So?
Beide Perspektiven legen nahe, dass das Zusammenhalten von Tests helfen kann, aber nicht schadet.
quelle