Wenn ich eine Funktion in meinem Code habe, die wie folgt aussieht:
class Employee{
public string calculateTax(string name, int salary)
{
switch (name)
{
case "Chris":
doSomething($salary);
case "David":
doSomethingDifferent($salary);
case "Scott":
doOtherThing($salary);
}
}
Normalerweise würde ich dies umgestalten, um Ploymorphism unter Verwendung einer Fabrikklasse und eines Strategiemusters zu verwenden:
public string calculateTax(string name)
{
InameHandler nameHandler = NameHandlerFactory::getHandler(name);
nameHandler->calculateTax($salary);
}
Wenn ich jetzt TDD verwenden würde, hätte ich calculateTax()
vor dem Refactoring einige Tests, die mit dem Original funktionieren .
Ex:
calculateTax_givenChrisSalaryBelowThreshold_Expect111(){}
calculateTax_givenChrisSalaryAboveThreshold_Expect111(){}
calculateTax_givenDavidSalaryBelowThreshold_Expect222(){}
calculateTax_givenDavidSalaryAboveThreshold_Expect222(){}
calculateTax_givenScottSalaryBelowThreshold_Expect333(){}
calculateTax_givenScottSalaryAboveThreshold_Expect333(){}
Nach dem Refactoring habe ich eine Factory-Klasse NameHandlerFactory
und mindestens 3 Implementierungen von InameHandler
.
Wie soll ich vorgehen, um meine Tests zu überarbeiten? Soll ich den Unit - Test für löschen claculateTax()
aus EmployeeTests
und eine Test - Klasse für jede Implementierung schaffen InameHandler
?
Soll ich auch die Factory-Klasse testen?
salary
zur FunktioncalculateTax()
hinzugefügt. Auf diese Weise werde ich wahrscheinlich den Testcode für die ursprüngliche Funktion und die 3 Implementierungen der Strategieklasse duplizieren.Ich beginne damit, dass ich kein Experte für TDD oder Unit-Tests bin, aber hier ist, wie ich dies testen würde (ich werde pseudoähnlichen Code verwenden):
Also würde ich prüfen , dass die
calculateTax()
Methode der Mitarbeiterklasse ihre korrekt fragtNameHandlerFactory
für einNameHandler
und ruft dann diecalculateTax()
Methode des zurückNameHandler
.quelle
Employee.calculateTax()
Methode erneut zu testen . Auf diese Weise müssen Sie keine zusätzlichen Mitarbeitertests hinzufügen, wenn Sie einen neuen NameHandler einführen.Sie nehmen an einer Klasse teil (Mitarbeiter, der alles macht) und bilden drei Gruppen von Klassen: die Fabrik, den Mitarbeiter (der nur eine Strategie enthält) und die Strategien.
Machen Sie also 3 Gruppen von Tests:
Sie können natürlich automatisierte Tests für den gesamten Shebang durchführen, aber diese sind jetzt eher Integrationstests und sollten als solche behandelt werden.
quelle
Bevor ich Code schreibe, beginne ich mit einem Test für eine Fabrik. Wenn ich mich über das Zeug lustig mache, das ich brauche, würde ich mich zwingen, über die Implementierungen und Verwendungszwecke nachzudenken.
Dann würde ich eine Factory implementieren und mit einem Test für jede Implementierung und schließlich den Implementierungen selbst für diese Tests fortfahren.
Schließlich würde ich die alten Tests entfernen.
quelle
Meiner Meinung nach sollten Sie nichts tun, dh Sie sollten keine neuen Tests hinzufügen.
Ich betone, dass dies eine Meinung ist und tatsächlich davon abhängt, wie Sie die Erwartungen an das Objekt wahrnehmen. Denken Sie, dass der Benutzer der Klasse eine Strategie für die Steuerberechnung liefern möchte? Wenn es ihn nicht interessiert, sollten die Tests dies widerspiegeln, und das Verhalten, das sich aus den Komponententests ergibt, sollte sein, dass es ihnen egal sein sollte, dass die Klasse begonnen hat, ein Strategieobjekt zur Berechnung der Steuer zu verwenden.
Ich bin tatsächlich mehrmals auf dieses Problem gestoßen, als ich TDD verwendet habe. Ich denke, der Hauptgrund ist, dass ein Strategieobjekt keine natürliche Abhängigkeit ist, im Gegensatz zu einer Abhängigkeit von Architekturgrenzen wie einer externen Ressource (einer Datei, einer Datenbank, einem Remotedienst usw.). Da es sich nicht um eine natürliche Abhängigkeit handelt, stütze ich das Verhalten meiner Klasse normalerweise nicht auf diese Strategie. Mein Instinkt ist, dass ich meine Tests nur ändern sollte, wenn sich die Erwartungen an meine Klasse geändert haben.
Es gibt einen großartigen Beitrag von Onkel Bob, der genau über dieses Problem bei der Verwendung von TDD spricht.
Ich denke, dass die Tendenz, jede einzelne Klasse zu testen, TDD tötet. Das Schöne an TDD ist, dass Sie Tests verwenden, um Designschemata voranzutreiben, und nicht umgekehrt.
quelle