Sollten die erwarteten Ergebnisse eines Komponententests fest codiert werden, oder können sie von initialisierten Variablen abhängen? Erhöhen hartcodierte oder berechnete Ergebnisse das Risiko von Fehlern im Komponententest? Gibt es andere Faktoren, die ich nicht berücksichtigt habe?
Welches dieser beiden Formate ist beispielsweise zuverlässiger?
[TestMethod]
public void GetPath_Hardcoded()
{
MyClass target = new MyClass("fields", "that later", "determine", "a folder");
string expected = "C:\\Output Folder\\fields\\that later\\determine\\a folder";
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
[TestMethod]
public void GetPath_Softcoded()
{
MyClass target = new MyClass("fields", "that later", "determine", "a folder");
string expected = "C:\\Output Folder\\" + string.Join("\\", target.Field1, target.Field2, target.Field3, target.Field4);
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
EDIT 1: Ist Option 3 als Antwort auf die Antwort von DXM eine bevorzugte Lösung?
[TestMethod]
public void GetPath_Option3()
{
string field1 = "fields";
string field2 = "that later";
string field3 = "determine";
string field4 = "a folder";
MyClass target = new MyClass(field1, field2, field3, field4);
string expected = "C:\\Output Folder\\" + string.Join("\\", field1, field2, field3, field4);
string actual = target.GetPath();
Assert.AreEqual(expected, actual,
"GetPath should return a full directory path based on its fields.");
}
c#
unit-testing
Hand-E-Food
quelle
quelle
Antworten:
Ich denke, berechnete Erwartungswerte ergeben robustere und flexiblere Testfälle. Auch durch die Verwendung guter Variablennamen in dem Ausdruck, der das erwartete Ergebnis berechnet, wird viel klarer, woher das erwartete Ergebnis überhaupt stammt.
Abgesehen davon würde ich in Ihrem speziellen Beispiel der "Softcoded" -Methode NICHT vertrauen, da sie Ihr zu testendes SUT (System) als Eingabe für Ihre Berechnungen verwendet. Wenn in MyClass ein Fehler auftritt, bei dem Felder nicht ordnungsgemäß gespeichert werden, besteht der Test tatsächlich, da bei der Berechnung des erwarteten Werts genau wie bei target.GetPath () die falsche Zeichenfolge verwendet wird.
Mein Vorschlag wäre, den erwarteten Wert dort zu berechnen, wo es Sinn macht, aber sicherzustellen, dass die Berechnung nicht von einem Code des SUT selbst abhängt.
Als Antwort auf die Aktualisierung von OP auf meine Antwort:
Ja, aufgrund meines Wissens, aber der begrenzten Erfahrung mit TDD, würde ich Option 3 wählen.
quelle
Was ist, wenn der Code wie folgt lautet:
Ihr zweites Beispiel würde den Fehler nicht erkennen, das erste Beispiel jedoch.
Im Allgemeinen würde ich gegen Soft-Codierung empfehlen, da es Fehler verbergen kann. Beispielsweise:
Können Sie das Problem erkennen? In einer hartkodierten Version würden Sie nicht denselben Fehler machen. Es ist schwieriger, die Berechnungen korrekt zu machen als hartcodierte Werte. Deshalb arbeite ich lieber mit hartcodierten Werten als mit weichcodierten.
Aber es gibt Ausnahmen. Was ist, wenn Ihr Code unter Windows und Linux ausgeführt werden muss? Der Pfad muss nicht nur unterschiedlich sein, er muss auch unterschiedliche Pfadtrennzeichen verwenden! Die Berechnung des Pfads mithilfe von Funktionen, die den Unterschied abstrahieren, kann in diesem Kontext sinnvoll sein.
quelle
Meiner Meinung nach sind Ihre beiden Vorschläge alles andere als ideal. Der ideale Weg, dies zu tun, ist dieser:
Mit anderen Worten, der Test sollte ausschließlich auf der Grundlage der Eingabe und der Ausgabe des Objekts und nicht auf der Grundlage des internen Zustands des Objekts funktionieren. Das Objekt sollte als Blackbox behandelt werden. (Ich ignoriere andere Probleme, wie die Unangemessenheit der Verwendung von string.Join anstelle von Path.Combine, da dies nur ein Beispiel ist.)
quelle
target.Dispose(); Assert.IsTrue(target.IsDisposed);
(ein sehr einfaches Beispiel.)Es gibt zwei Aspekte in der Diskussion:
1. Verwenden des Ziels selbst für den Testfall
Die erste Frage ist, ob Sie die Klasse selbst verwenden können, um sich auf die im Teststub geleistete Arbeit zu verlassen und einen Teil davon zu erhalten. - Die Antwort lautet NEIN, da Sie im Allgemeinen niemals eine Annahme über den Code machen sollten, den Sie testen. Wenn dies nicht richtig gemacht wird, werden Bugs im Laufe der Zeit immun gegen einige Unit-Tests.
2. Hardcoding
sollten Sie hart codieren ? Wieder lautet die Antwort Nein . Denn wie bei jeder Software wird die harte Kodierung der Informationen schwierig, wenn sich die Dinge weiterentwickeln. Wenn Sie beispielsweise möchten, dass der oben genannte Pfad erneut geändert wird, müssen Sie entweder eine zusätzliche Einheit schreiben oder die Änderung fortsetzen. Eine bessere Methode besteht darin, das Eingabe- und Auswertungsdatum aus der separaten Konfiguration abzuleiten, die einfach angepasst werden kann.
Zum Beispiel ist hier, wie ich den Teststummel richtig machen würde.
quelle
Es sind viele Konzepte möglich, die anhand einiger Beispiele den Unterschied erkennen lassen
Um es zusammenzufassen: Im Allgemeinen ist Ihr erster, nur fest codierter Test für mich am sinnvollsten, da er einfach ist, direkt auf den Punkt kommt usw. Wenn Sie einen Pfad zu oft fest codieren, geben Sie ihn einfach in die Setup-Methode ein.
Für zukünftige strukturierte Tests würde ich Datenquellen auschecken, sodass Sie einfach weitere Datenzeilen hinzufügen können, wenn Sie mehr Testsituationen benötigen.
quelle
Moderne Test-Frameworks ermöglichen es Ihnen, Parameter für Ihre Methode bereitzustellen. Ich würde diese nutzen:
Dies hat aus meiner Sicht mehrere Vorteile:
quelle