Ich bevorzuge Klassen, die Zeit verwenden und tatsächlich auf einer Schnittstelle basieren, wie z
interface IClock
{
DateTime Now { get; }
}
Mit einer konkreten Umsetzung
class SystemClock: IClock
{
DateTime Now { get { return DateTime.Now; } }
}
Wenn Sie möchten, können Sie jede andere Art von Uhr zum Testen bereitstellen, z
class StaticClock: IClock
{
DateTime Now { get { return new DateTime(2008, 09, 3, 9, 6, 13); } }
}
Die Bereitstellung der Uhr für die darauf basierende Klasse kann mit einem gewissen Aufwand verbunden sein, der jedoch von einer beliebigen Anzahl von Abhängigkeitsinjektionslösungen (unter Verwendung eines Inversion of Control-Containers, einer einfachen alten Konstruktor- / Setter-Injektion oder sogar eines statischen Gateway-Musters) verarbeitet werden kann ).
Andere Mechanismen zur Bereitstellung eines Objekts oder einer Methode, die die gewünschten Zeiten liefern, funktionieren ebenfalls, aber ich denke, das Wichtigste ist, ein Zurücksetzen der Systemuhr zu vermeiden, da dies nur auf anderen Ebenen zu Schmerzen führen wird.
Die Verwendung DateTime.Now
und Einbeziehung in Ihre Berechnungen fühlt sich nicht nur nicht richtig an, sondern raubt Ihnen auch die Möglichkeit, bestimmte Zeiten zu testen, z. B. wenn Sie einen Fehler entdecken, der nur in der Nähe einer Mitternachtsgrenze oder dienstags auftritt. Wenn Sie die aktuelle Zeit verwenden, können Sie diese Szenarien nicht testen. Oder zumindest nicht wann immer Sie wollen.
UtcNow
verwendet und dann entsprechend den Anforderungen des Codes angepasst werden sollte, z. B. Geschäftslogik, Benutzeroberfläche usw. Die Manipulation von DateTime über Zeitzonen hinweg ist ein Minenfeld, aber der beste erste Schritt ist, immer damit zu beginnen UTC-Zeit.Ayende Rahien verwendet eine statische Methode, die ziemlich einfach ist ...
quelle
Ich denke, eine separate Uhrenklasse für etwas Einfaches wie das Abrufen des aktuellen Datums zu erstellen, ist etwas übertrieben.
Sie können das heutige Datum als Parameter übergeben, um ein anderes Datum in den Test einzugeben. Dies hat den zusätzlichen Vorteil, dass Ihr Code flexibler wird.
quelle
Die Verwendung von Microsoft Fakes zum Erstellen eines Shims ist eine sehr einfache Möglichkeit, dies zu tun. Angenommen, ich hätte die folgende Klasse:
In Visual Studio 2012 können Sie Ihrem Testprojekt eine Fakes-Assembly hinzufügen, indem Sie mit der rechten Maustaste auf die Assembly klicken, für die Sie Fakes / Shims erstellen möchten, und "Fakes-Assembly hinzufügen" auswählen.
Zum Schluss würde die Testklasse folgendermaßen aussehen:
quelle
Der Schlüssel zum erfolgreichen Unit-Test ist die Entkopplung . Sie müssen Ihren interessanten Code von seinen externen Abhängigkeiten trennen, damit er isoliert getestet werden kann. (Glücklicherweise erzeugt testgetriebene Entwicklung entkoppelten Code.)
In diesem Fall ist Ihr externes Datum die aktuelle DateTime.
Mein Rat hier ist, die Logik, die sich mit der DateTime befasst, auf eine neue Methode oder Klasse oder was auch immer in Ihrem Fall sinnvoll ist, zu extrahieren und die DateTime zu übergeben. Jetzt kann Ihr Komponententest eine beliebige DateTime übergeben, um vorhersagbare Ergebnisse zu erzielen.
quelle
Eine andere mit Microsoft Moles ( Isolation Framework für .NET ).
quelle
Ich würde vorschlagen, ein IDisposable-Muster zu verwenden:
Im Detail hier beschrieben: http://www.lesnikowski.com/blog/index.php/testing-datetime-now/
quelle
Einfache Antwort: ditch System.DateTime :) Verwenden Sie stattdessen NodaTime und die Testbibliothek : NodaTime.Testing .
Weiterführende Literatur:
quelle
Sie können die Klasse (besser: Methode / Delegat ), für die Sie
DateTime.Now
in der getesteten Klasse verwenden, einfügen. HabenDateTime.Now
ein Standardwert und setzen Sie ihn beim Testen nur auf eine Dummy-Methode, die einen konstanten Wert zurückgibt.EDIT: Was Blair Conrad gesagt hat (er hat einen Code zum Anschauen). Außer, ich bevorzuge Delegierte dafür, da sie Ihre Klassenhierarchie nicht mit Dingen wie
IClock
...quelle
Ich war so oft mit dieser Situation konfrontiert, dass ich ein einfaches Nuget erstellt habe, das die Now- Eigenschaft über die Schnittstelle verfügbar macht .
Die Implementierung ist natürlich sehr einfach
Nachdem ich meinem Projekt Nuget hinzugefügt habe, kann ich es in den Unit-Tests verwenden
Sie können das Modul direkt über den GUI Nuget Package Manager oder mit dem folgenden Befehl installieren:
Und der Code für das Nuget ist hier .
Das Beispiel für die Verwendung mit dem Autofac finden Sie hier .
quelle
Haben Sie darüber nachgedacht, die bedingte Kompilierung zu verwenden, um zu steuern, was während des Debuggens / Bereitstellens passiert?
z.B
Wenn Sie dies nicht tun, möchten Sie die Eigenschaft verfügbar machen, damit Sie sie manipulieren können. Dies ist alles Teil der Herausforderung, testbaren Code zu schreiben , was ich derzeit selbst ringe: D.
Bearbeiten
Ein großer Teil von mir würde Blairs Ansatz bevorzugen . Auf diese Weise können Sie Teile des Codes "Hot Plug", um das Testen zu erleichtern. Es folgt alles dem Entwurfsprinzip , das die Unterschiede zusammenfasst unterscheidet. Es unterscheidet sich nicht vom Produktionscode. Es wird nur niemand jemals extern sehen.
Das Erstellen und die Benutzeroberfläche scheinen für dieses Beispiel jedoch eine Menge Arbeit zu sein (weshalb ich mich für die bedingte Kompilierung entschieden habe).
quelle
DateTime
istNow
undToday
usw.