Ich teste eine Methode, die eine Sammlung von Datenobjekten erzeugen soll. Ich möchte überprüfen, ob die Eigenschaften der Objekte korrekt eingestellt sind. Einige der Eigenschaften werden auf dasselbe festgelegt. andere werden auf einen Wert gesetzt, der von ihrer Position in der Sammlung abhängt. Der natürliche Weg, dies zu tun, scheint eine Schleife zu sein. Roy Osherove rät jedoch nachdrücklich von der Verwendung von Logik in Komponententests ab ( Art of Unit Testing , 178). Er sagt:
Ein Test, der Logik enthält, testet normalerweise mehr als eine Sache gleichzeitig, was nicht empfohlen wird, da der Test weniger lesbar und anfälliger ist. Die Testlogik erhöht jedoch auch die Komplexität, die einen versteckten Fehler enthalten kann.
Tests sollten in der Regel eine Reihe von Methodenaufrufen ohne Kontrollflüsse (auch nicht)
try-catch
und mit Assert-Aufrufen sein.
An meinem Design kann ich jedoch nichts Falsches erkennen (wie sonst generieren Sie eine Liste von Datenobjekten, von deren Werten einige in der Reihenfolge abhängen, in der sie sich befinden? - Sie können sie nicht exakt separat generieren und testen). Gibt es etwas nicht testfreundliches an meinem Design? Oder widme ich mich zu sehr Osheroves Lehre? Oder gibt es eine geheime Unit-Test-Magie, die ich nicht kenne, um dieses Problem zu umgehen? (Ich schreibe in C # / VS2010 / NUnit, suche aber wenn möglich nach sprachunabhängigen Antworten.)
quelle
in
) erforderlich machen, wenn der Test "Frob wurde erfolgreich zu einer vorhandenen Sammlung hinzugefügt" lautet.toString()
die Sammlung und vergleiche mit dem, was es sein sollte. Einfach und funktioniert.Antworten:
TL; DR:
Das erste, was getestet werden muss, ist, dass das Dogma nicht hilfreich ist. Ich lese gerne den Weg des Testivus, der auf unbeschwerte Art und Weise auf einige Probleme mit dem Dogma hinweist.
Wenn der Test auf irgendeine Weise geschrieben werden muss, schreiben Sie ihn auf diese Weise. Der Versuch, den Test in ein idealisiertes Testlayout zu zwingen oder gar nicht zu haben, ist keine gute Sache. Ein Test heute, der es testet, ist besser als ein "perfekter" Test eines späteren Tages.
Ich werde auch auf den hässlichen Test hinweisen:
Dies kann als Binsenweisheit für diejenigen angesehen werden, die schon lange folgen ... und sie werden nur in der Art des Denkens und Schreibens von Tests verankert. Für Leute, die noch nicht an diesen Punkt gekommen sind und dies versuchen, können Erinnerungen hilfreich sein (ich finde sogar, dass ein erneutes Lesen mir hilft, mich nicht auf ein Dogma einzulassen).
Bedenken Sie beim Schreiben eines hässlichen Tests, dass der Code möglicherweise darauf hinweist, dass er zu viel zu tun versucht. Wenn der zu testende Code zu komplex ist, um durch Schreiben eines einfachen Tests ordnungsgemäß ausgeführt zu werden, können Sie den Code in kleinere Teile aufteilen, die mit den einfacheren Tests getestet werden können. Man sollte nicht einen Unit - Test schreiben, der alles tut (es kann nicht sein , Einheit Test dann). So wie "Gottobjekte" schlecht sind, sind auch "Gotteinheitentests" schlecht und sollten Hinweise sein, den Code noch einmal anzusehen.
Sie sollten in der Lage sein, den gesamten Code durch solche einfachen Tests mit angemessener Abdeckung auszuüben. Tests, die mehr End-to-End-Tests durchführen, die sich mit größeren Fragen befassen ("Ich habe dieses Objekt in XML zusammengefasst, über die Regeln an den Webdienst gesendet, zurückgesetzt und nicht zusammengefasst"), sind ein ausgezeichneter Test - aber sicher nicht ist kein Komponententest (und fällt in den Bereich der Integrationstests - auch wenn er Dienste verspottet hat, die er aufruft und die für den Test in Speicherdatenbanken benutzerdefiniert sind). Möglicherweise wird das XUnit-Framework weiterhin zum Testen verwendet, das Testing-Framework macht es jedoch nicht zu einem Komponententest.
quelle
Ich füge eine neue Antwort hinzu, weil meine Perspektive sich von der unterscheidet, als ich die ursprüngliche Frage und Antwort geschrieben habe. es macht keinen Sinn, sie zu einer zusammenzufassen.
Ich sagte in der ursprünglichen Frage
Hier habe ich mich geirrt. Nachdem ich im letzten Jahr die Funktionsprogrammierung durchgeführt hatte, wurde mir klar, dass ich nur eine Sammeloperation mit einem Akku benötigte. Dann könnte ich meine Funktion als reine Funktion schreiben, die auf eine Sache abzielt, und eine Standardbibliotheksfunktion verwenden, um sie auf die Sammlung anzuwenden.
Meine neue Antwort lautet also: Verwende funktionale Programmiertechniken und du wirst dieses Problem die meiste Zeit ganz vermeiden. Sie können Ihre Funktionen schreiben, um einzelne Dinge zu bearbeiten und sie erst im letzten Moment auf Sammlungen von Dingen anzuwenden. Wenn sie jedoch rein sind, können Sie sie ohne Bezugnahme auf Sammlungen testen.
Verlassen Sie sich für komplexere Logik auf eigenschaftsbasierte Tests . Wenn sie über eine Logik verfügen, sollte diese kleiner sein als die Logik des getesteten Codes und umgekehrt, und bei jedem Test wird so viel mehr überprüft als bei einem fallbasierten Komponententest, dass sich die geringe Menge an Logik lohnt.
Vor allem stützen Sie sich immer auf Ihre Typen . Holen Sie sich die stärksten Typen, die Sie können, und nutzen Sie sie zu Ihrem Vorteil. Dies reduziert die Anzahl der Tests, die Sie zuerst schreiben müssen.
quelle
Versuchen Sie nicht, zu viele Dinge gleichzeitig zu testen. Jede der Eigenschaften jedes Datenobjekts in der Auflistung ist zu viel für einen Test. Stattdessen empfehle ich:
Auf diese Weise werden die Tests so klein, dass das Weglassen von Schleifen nicht schmerzhaft erscheint. C # / Unit-Beispiel, gegebene Testmethode
ICollection<Foo> generateFoos(uint numberOfFoos)
:Wenn Sie an das "Flat Unit Test" -Paradigma (keine verschachtelten Strukturen / Logik) gewöhnt sind, scheinen diese Tests ziemlich sauber zu sein. Somit wird Logik in den Tests vermieden, indem das ursprüngliche Problem als der Versuch erkannt wird, zu viele Eigenschaften gleichzeitig zu testen, anstatt dass Schleifen fehlen.
quelle