5 votes

Système informatique fictif Date Heure

J'ai construit un service Windows en C# qui appelle des données de séries temporelles en temps réel à partir d'une base de données en fonction de la date et de l'heure actuelles.
J'ai des données de test dans une base de données de test que j'aimerais utiliser pour calculer si les données sont utilisées correctement.
Je me demandais si quelqu'un avait utilisé une application ou un autre moyen pour "simuler" la date du système sur votre ordinateur local. Par exemple, je peux lancer cette application et la configurer pour qu'elle fixe la date de mon système à une date précise.

Tout conseil serait le bienvenu.

12voto

sloth Points 40517

Il suffit d'encapsuler votre accès au DateTime.Now derrière une interface.

public interface IDateTimeProvider
{
    DateTime Now { get; }
}

Dans votre code, utilisez une implémentation comme celle-ci :

public class DateTimeProvider : IDateTimeProvider
{
    public DateTime Now { get { return DateTime.Now; } }
}

Et pour vos tests, vous pouvez simplement simuler IDateTimeProvider en créant une classe de test ou en utilisant un cadre de simulation.

Si vous utilisez cette interface avec une technique comme l'injection de dépendance, il est facile de modifier le comportement de votre service, même au moment de l'exécution.

Vous pouvez par exemple créer un IDateTimeProvider qui est toujours à quelques heures près :

public class AlwaysToLateDateTimeProvider : IDateTimeProvider
{
    public DateTime Now { get { return DateTime.Now.AddHours(-2); } }
}

ou créer une implémentation qui lit la date "simulée" à partir d'un fichier, d'une base de données, d'un tuyau, etc.

Lors des tests, vous configurerez votre service pour qu'il utilise l'une de ces implémentations, et lors de l'exécution en mode réel, vous configurerez simplement votre injection de dépendance pour qu'elle utilise l'implémentation ordinaire qui renvoie la "bonne" date et l'heure.


Et il y a bien sûr Isolateur TypeMock ...

Isolate.WhenCalled(() => DateTime.Now).WillReturn(new DateTime(2008, 1, 1));

4voto

Mharlin Points 1446

Je l'ai utilisé pour pouvoir ignorer maintenant, par exemple lors de l'exécution de tests. Dans votre implémentation réelle où vous utilisez DateTime.Now, vous utilisez le nouveau SystemTime.Now à la place. Dans vos tests, il vous suffit de définir Now dans une fonction différente qui renvoie la valeur de votre choix.

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

    public static Func<DateTime> Now
    {
        get { return now; }
        set { now = value; }
    }
}

Exemple d'utilisation en test :

SystemTime.Now = () => DateTime.Now.AddMinutes(20);

Dans le démontage du test unitaire, il est important de le remettre en place avec SystemTime.Now = () => DateTime.Now

Utilisation normale :

DateTime now = SystemTime.Now();

0voto

JonathanK Points 1680

À l'instar de la solution proposée par Mharlin, l'implémentation ci-dessous permet de remplacer une fois pour toutes la fonction DateTime.Now . Ce qui a été ajouté, ce sont quelques méthodes de commodité pour manipuler le temps dans les tests unitaires. Ce qui a été modifié, c'est la nécessité d'exécuter explicitement l'action qui renvoie une valeur de DateTime qui ressemble davantage à DateTime.Now l'utilisation.

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

    public static DateTime Now
    {
        get { return now(); }
    }

    public static void Set(DateTime dt)
    {
        now = () => dt;
    }

    public static void MoveForward(TimeSpan ts)
    {
        var dt = now().Add(ts);
        Set(dt);
    }

    public static void Reset()
    {
        now = () => DateTime.Now;
    }
}

Exemple d'utilisation dans le code de production :

var twentyMinutesFromNow = SystemTime.Now.AddMinutes(20);

Exemple d'utilisation dans un test sensible au temps (celui-ci vérifie l'expiration du cache) :

// Set(): effectively lock the system clock at a specific time
SystemTime.Set(new DateTime(2015, 1, 1));

RunCodeThatFetchesDataAndCachesIt();

// MoveForward(): easily move the clock relative to current time with an
//  arbitrary TimeSpan
SystemTime.MoveForward(TimeSpan.FromMinutes(1));

RunCodeThatFetchesDataAndCachesIt();
VerifyExpectationThatDataWasFetchedTwice();

// Reset(): return to the normal behavior of returning the current
//   DateTime.Now value
SystemTime.Reset();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X