Ma préférence est que les classes qui utilisent le temps reposent en fait sur une interface, telle que
interface IClock
{
DateTime Now { get; }
}
Avec une mise en œuvre concrète
class SystemClock: IClock
{
DateTime Now { get { return DateTime.Now; } }
}
Ensuite, si vous le souhaitez, vous pouvez fournir tout autre type d'horloge que vous souhaitez pour le test, tel que
class StaticClock: IClock
{
DateTime Now { get { return new DateTime(2008, 09, 3, 9, 6, 13); } }
}
Il peut y avoir une surcharge à fournir l'horloge à la classe qui en dépend, mais cela pourrait être géré par n'importe quel nombre de solutions d'injection de dépendances (en utilisant un conteneur d'inversion de contrôle, une ancienne injection de constructeur / setter, ou même un modèle de passerelle statique ).
D'autres mécanismes de livraison d'un objet ou d'une méthode qui fournit les heures souhaitées fonctionnent également, mais je pense que l'essentiel est d'éviter de réinitialiser l'horloge système, car cela ne fera qu'introduire de la douleur à d'autres niveaux.
De plus, l'utiliser DateTime.Now
et l'inclure dans vos calculs ne vous semble pas juste - cela vous prive de la possibilité de tester des moments particuliers, par exemple si vous découvrez un bogue qui ne se produit que près d'une limite de minuit ou le mardi. L'utilisation de l'heure actuelle ne vous permettra pas de tester ces scénarios. Ou du moins pas quand vous le souhaitez.
UtcNow
devrait être utilisé puis ajusté de manière appropriée en fonction des préoccupations du code, par exemple la logique métier, l'interface utilisateur, etc. Heure UTC.Ayende Rahien utilise une méthode statique assez simple ...
la source
Je pense que créer une classe d'horloge séparée pour quelque chose de simple comme obtenir la date actuelle est un peu exagéré.
Vous pouvez transmettre la date du jour en tant que paramètre afin de pouvoir saisir une date différente dans le test. Cela présente l'avantage supplémentaire de rendre votre code plus flexible.
la source
L'utilisation de Microsoft Fakes pour créer un shim est un moyen très simple de le faire. Supposons que j'ai eu le cours suivant:
Dans Visual Studio 2012, vous pouvez ajouter un assemblage Fakes à votre projet de test en cliquant avec le bouton droit sur l'assemblage pour lequel vous souhaitez créer Fakes / Shims et en sélectionnant «Ajouter un assemblage Fakes»
Enfin, voici à quoi ressemblerait la classe de test:
la source
La clé du succès des tests unitaires est le découplage . Vous devez séparer votre code intéressant de ses dépendances externes, afin qu'il puisse être testé isolément. (Heureusement, le développement piloté par les tests produit du code découplé.)
Dans ce cas, votre externe est le DateTime actuel.
Mon conseil ici est d'extraire la logique qui traite le DateTime vers une nouvelle méthode ou classe ou tout ce qui a du sens dans votre cas, et de passer le DateTime. Maintenant, votre test unitaire peut passer un DateTime arbitraire, pour produire des résultats prévisibles.
la source
Un autre utilisant Microsoft Moles ( Isolation Framework for .NET ).
la source
Je suggère d'utiliser le modèle IDisposable:
En détail décrit ici: http://www.lesnikowski.com/blog/index.php/testing-datetime-now/
la source
Réponse simple: abandonnez System.DateTime :) Au lieu de cela, utilisez NodaTime et sa bibliothèque de test: NodaTime.Testing .
Lectures complémentaires:
la source
Vous pouvez injecter la classe (mieux: méthode / délégué ) que vous utilisez
DateTime.Now
dans la classe testée. AvoirDateTime.Now
une valeur par défaut et ne la définir dans le test que sur une méthode factice qui renvoie une valeur constante.EDIT: Ce que Blair Conrad a dit (il a du code à regarder). Sauf que j'ai tendance à préférer les délégués pour cela, car ils n'encombrent pas votre hiérarchie de classe avec des trucs comme
IClock
...la source
J'ai fait face à cette situation si souvent, que j'ai créé un simple nuget qui expose la propriété Now via l'interface.
La mise en œuvre est bien sûr très simple
Donc, après avoir ajouté nuget à mon projet, je peux l'utiliser dans les tests unitaires
Vous pouvez installer le module directement à partir du gestionnaire de packages GUI Nuget ou en utilisant la commande:
Et le code pour le Nuget est ici .
L'exemple d'utilisation avec l'Autofac peut être trouvé ici .
la source
Avez-vous envisagé d'utiliser la compilation conditionnelle pour contrôler ce qui se passe pendant le débogage / le déploiement?
par exemple
À défaut, vous voulez exposer la propriété afin de pouvoir la manipuler, tout cela fait partie du défi d'écrire du code testable , ce que je lutte moi-même actuellement: D
Éditer
Une grande partie de moi préférerait l'approche de Blair . Cela vous permet de «connecter à chaud» des parties du code pour faciliter les tests. Tout suit le principe de conception: encapsuler ce qui varie le code de test n'est pas différent du code de production, c'est juste que personne ne le voit jamais de l'extérieur.
La création et l'interface peuvent sembler beaucoup de travail pour cet exemple (c'est pourquoi j'ai opté pour la compilation conditionnelle).
la source
DateTime
lesNow
etToday
etc.