Frage

Ich habe einige C# - code, der setzt auf das heutige Datum, um korrekt zu berechnen, die Dinge in der Zukunft.Wenn ich das heutige Datum in der Prüfung, ich muss wiederholen Sie die Berechnung in der Prüfung, das fühlt sich nicht richtig an.Was ist der beste Weg, um das Datum auf einen bekannten Wert im test, so dass ich testen kann, dass das Ergebnis einen bekannten Wert?

War es hilfreich?

Lösung

Meine Vorliebe zu haben Klassen mit der Zeit tatsächlich verlassen sich auf eine Schnittstelle, wie

interface IClock
{
    DateTime Now { get; } 
}

Mit einem konkreten Umsetzung

class SystemClock: IClock
{
     DateTime Now { get { return DateTime.Now; } }
}

Dann, wenn Sie möchten, können Sie jede andere Art von Uhr, die Sie zum testen, wie

class StaticClock: IClock
{
     DateTime Now { get { return new DateTime(2008, 09, 3, 9, 6, 13); } }
}

Es kann ein gewisser Aufwand in der Versorgung der Uhr für die-Klasse, die sich auf Sie, aber Sie kann behandelt werden, indem eine beliebige Anzahl von dependency injection-Lösungen (mit einer Inversion of Control container, plain old Konstruktor/setter-Injektion, oder sogar ein Statische Gateway-Muster).

Andere Mechanismen liefern ein Objekt oder eine Methode, die bietet gewünschten Zeiten auch funktionieren, aber ich denke, der Schlüssel ist, zu vermeiden zurücksetzen der system-Uhr, wie nur vorstellen Schmerz auf anderen Ebenen.

Auch mit DateTime.Now und wie es in Ihre Berechnungen nicht nur nicht im Recht fühlen - es raubt Ihnen die Fähigkeit zu testen, bestimmten Zeiten, zum Beispiel, wenn Sie entdecken, dass ein Fehler, der passiert nur in der Nähe einer Mitternacht Grenze, oder dienstags.Verwenden Sie die aktuelle Zeit können Sie nicht testen Sie diese Szenarien.Oder zumindest nicht, Wann immer Sie wollen.

Andere Tipps

Ayende Rahien verwendet eine statische Methode ist ziemlich einfach...

public static class SystemTime
{
    public static Func<DateTime> Now = () => DateTime.Now;
}

Ich denke, das erstellen einer separaten Uhr Klasse für etwas einfaches wie das immer das aktuelle Datum ist ein bisschen übertrieben.

Übergeben Sie das heutige Datum als parameter, so können Sie geben Sie ein anderes Datum im test.Dies hat den zusätzlichen Vorteil, dass Sie Ihren code flexibler.

Mithilfe von Microsoft Fälschungen zu erstellen, die ein shim ist ein wirklich einfacher Weg, dies zu tun.Angenommen, ich hatte die folgende Klasse:

public class MyClass
{
    public string WhatsTheTime()
    {
        return DateTime.Now.ToString();
    }

}

In Visual Studio 2012 können Sie einen Fälschungen Montage zu Ihre test-Projekt mit der rechten Maustaste auf die assembly, die Sie erstellen möchten Fakes/Beilagen und wählen Sie "Add Fakes-Assembly"

Adding Fakes Assembly

Schließlich, Hier ist das, was der test-Klasse Aussehen würde:

using System;
using ConsoleApplication11;
using Microsoft.QualityTools.Testing.Fakes;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DateTimeTest
{
[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestWhatsTheTime()
    {

        using(ShimsContext.Create()){

            //Arrange
            System.Fakes.ShimDateTime.NowGet =
            () =>
            { return new DateTime(2010, 1, 1); };

            var myClass = new MyClass();

            //Act
            var timeString = myClass.WhatsTheTime();

            //Assert
            Assert.AreEqual("1/1/2010 12:00:00 AM",timeString);

        }
    }
}
}

Der Schlüssel zu einer erfolgreichen unit-Tests ist Entkopplung.Sie haben zu trennen interessant code von seinen externen Abhängigkeiten, so dass es kann isoliert getestet werden.(Zum Glück, Test-Driven Development, produziert entkoppelt code.)

In diesem Fall, Ihre externe ist die aktuelle DateTime.

Mein Rat hier ist, extrahieren Sie die Logik, das sich mit der DateTime-um eine neue Methode oder Klasse oder was auch immer Sinn macht, in Ihrem Fall, und passieren die DateTime in.Nun, Ihre unit-test übergeben kann eine beliebige DateTime in, zu erzeugen vorhersagbare Ergebnisse.

Ein weiteres mit Microsoft Moles (Isolierung Rahmen für .NET).

MDateTime.NowGet = () => new DateTime(2000, 1, 1);

Muttermale können zu ersetzen .NET Methode mit einem Delegierten.Moles unterstützt statische oder nicht-virtuelle Methoden.Maulwürfe stützt sich auf die profiler von Pex.

Ich würde vorschlagen, mit IDisposable-Muster:

[Test] 
public void CreateName_AddsCurrentTimeAtEnd() 
{
    using (Clock.NowIs(new DateTime(2010, 12, 31, 23, 59, 00)))
    {
        string name = new ReportNameService().CreateName(...);
        Assert.AreEqual("name 2010-12-31 23:59:00", name);
    } 
}

Im detail hier beschrieben:http://www.lesnikowski.com/blog/index.php/testing-datetime-now/

Einfache Antwort:Graben-System.DateTime :) verwenden Sie Stattdessen NodaTime und es ist testing library: NodaTime.Prüfung.

Weiter Lesen:

Sie konnte Spritzen Sie die Klasse (besser:Methode/delegieren) verwenden Sie für DateTime.Now in der Klasse getestet.Haben DateTime.Now ein Standardwert, nur setzen es in der Prüfung um eine dummy-Methode, dass gibt eine Konstante Wert.

EDIT: Was Blair Conrad sagte (er hat einige code zu schauen).Außer, ich Neige zu bevorzugen, die Delegierten dafür, wie Sie don ' T clutter up your Klassenhierarchie mit Sachen wie IClock...

Ich Stand vor dieser situation so oft, dass ich erstellt einfache nuget, welche macht Jetzt Eigenschaft durch das interface.

public interface IDateTimeTools
{
    DateTime Now { get; }
}

Die Umsetzung ist natürlich sehr einfach

public class DateTimeTools : IDateTimeTools
{
    public DateTime Now => DateTime.Now;
}

So nach dem hinzufügen von nuget zu meinem Projekt, ich kann es benutzen in das unit-tests

enter image description here

Sie können installieren Sie das Modul direkt aus dem GUI-Nuget-Paket-Manager oder mit dem Befehl:

Install-Package -Id DateTimePT -ProjectName Project

Und der code für das Nuget ist hier.

Das Beispiel für die Verwendung mit der Autofac finden hier.

Haben Sie als bedingte Kompilierung zu kontrollieren, was passiert, während der debug - / - Bereitstellung?

z.B.

DateTime date;
#if DEBUG
  date = new DateTime(2008, 09, 04);
#else
  date = DateTime.Now;
#endif

Gelingt das nicht, werden Sie wollen, setzen die Immobilie, so können Sie es verändern, all dies ist Teil der Herausforderung des Schreibens testbar code, die ist etwas, was ich bin derzeit wrestling-mich :D

Bearbeiten

Ein großer Teil von mir würde Präferenz Blair Ansatz.Dadurch können Sie "hot-plug" Teile des Codes, um Hilfe bei der Prüfung.Alles folgt dem design-Prinzip Kapseln, was variiert test code ist nicht anders zu Produktions-code, es ist nur niemand sieht es nach außen.

Erstellen und Schnittstelle mag wie eine Menge Arbeit für dieses Beispiel aber (das ist, warum ich entschied mich für die bedingte Kompilierung).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top