Ich habe eine Klasse, die ich teste. Die Klasse hat eine Funktion:apply(List<IRule> rules, List<ITarget> targets);
In einem Test möchte ich sicherstellen, dass jedes Ziel an eine Regel übergeben wurde, a la:
rule1.AssertWasCalled(fnord => fnord.Test(target1));
rule1.AssertWasCalled(fnord => fnord.Test(target2));
rule1.AssertWasCalled(fnord => fnord.Test(target3));
Es scheint mir, dass es ein Hobgoblin wäre, mich auf eine einzige Aussage zu beschränken . Bin ich in dieser Annahme richtig oder gibt es eine andere Möglichkeit, um zu behaupten, dass jedes Ziel tatsächlich getestet wurde?
unit-testing
code-quality
Wayne Werner
quelle
quelle
Antworten:
Die drei Behauptungen sind im Wesentlichen ein Test. Sie testen das Verhalten einer Methode in einer Sammlung, um sicherzustellen, dass jedes Element ein Parameter für einen bestimmten Aufruf war (dh, dass jedes Element ordnungsgemäß verarbeitet wurde).
Das dreimalige Einrichten der Daten und drei verschiedene Methoden ist verschwenderisch und weniger lesbar als die Alternative, mehrere Asserts zu haben.
Bei der einzelnen Assert- "Regel" geht es mehr darum, Asserts unterschiedlichen Typs mit denselben Methoden zu erstellen (im Wesentlichen verschiedene Dinge zu testen). Dies gilt in diesem Fall nicht wirklich, wenn Sie auf ein einzelnes Verhalten testen.
quelle
Ich bin davon überzeugt, dass diese eine Behauptung pro Testregel existiert, um Ihre Tests auf ein Problem zu konzentrieren. Wenn Sie 20 Dinge in einem Test testen, ist es wirklich schwer zu sagen, wie hoch Ihre Abdeckung ist. Sie wissen, dass es ein Problem verursacht, wenn Sie die Testmethode nicht ohne das Wort und darin benennen können. Wenn Ihre Testmethode beispielsweise genauer benannt wäre, testen
testFooIsTrueAndDbExistsAndBarIsNullAndAnExceptionDoesntOccur()
Sie wahrscheinlich zu viel in einem Test.In Ihrem Fall denke ich, dass es wahrscheinlich in Ordnung ist, dreimal zu behaupten. Wenn Sie Ihren Code lesbarer machen möchten, können Sie diese drei Asserts in eine Methode mit dem Namen extrahieren
assertWasCalledOnTargets(...)
.quelle
Für Ihr spezielles Beispiel können Sie mit "einer" Assert-Anweisung davonkommen, wenn Sie Folgendes tun:
Es ist das, was ich tue, um zu vermeiden, dass ich mich schuldig fühle, wenn ich mehrere Behauptungen in einem Test habe.
quelle
Ich habe auch mit diesem gekämpft.
Der Purist (in mir) besteht auf einer Behauptung pro Test, damit ich * genau * weiß , wo die Dinge explodierten.
Und dann schneide / füge ich viel des gleichen redundanten Test-Setup-Codes ein. Nach der dritten oder vierten Schicht beginnen Sie zu sagen "Oy! Genug!"
Mein Kompromiss bestand darin, die Aspekte zu finden, die "nie" brechen. Und ich werde diese Teile zusammenfügen und dann ein neues Element hinzufügen , das brechen könnte. Um ganz klar zu sein, würde die Schichtung mehrerer flüchtiger Bereiche in einem Test einen Verstoß gegen diesen Kompromiss darstellen.
quelle
Assume
. Ich habe es heute gerade erfahren.Wenn sich der Setup-Code für
target1
vom Setup-Code für unterscheidettarget2
, führt diese Art des Eckenschneidens möglicherweise zu einem zu langen Testinitialisierungscode. Dies wiederum ist entweder ein Chaos oder wird überarbeitet und wiederverwendet. Wenn Ihre Tests komplex genug sind, um eine Umgestaltung zu rechtfertigen, testet Ihr Test wahrscheinlich mehr als eine Sache.Wenn der Setup-Code für jedes Ziel im Wesentlichen derselbe ist, ist die Aufteilung Ihres Tests in mehrere Einzeltests wahrscheinlich übertrieben.
Wenn
target1
undtarget2
verschiedene Implementierungen derselben Schnittstelle sind, sollten Sie stattdessen sein Hinzufügen einer Unit - Test an die Schnittstelle (und damit Ihre Test - Framework einen Test für jede Implementierung dieser Schnittstelle erzeugen).quelle