I\'ve got some (C#) code that relies on today\'s date to correctly calculate things in the future. If I use today\'s date in the testing, I have to repeat the calculation in
Using Microsoft Fakes to create a shim is a really easy way to do this. Suppose I had the following class:
public class MyClass
{
public string WhatsTheTime()
{
return DateTime.Now.ToString();
}
}
In Visual Studio 2012 you can add a Fakes assembly to your test project by right clicking on the assembly you want to create Fakes/Shims for and selecting "Add Fakes Assembly"
Finally, Here is what the test class would look like:
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);
}
}
}
}
Another one using Microsoft Moles (Isolation framework for .NET).
MDateTime.NowGet = () => new DateTime(2000, 1, 1);
Moles allows to replace any .NET method with a delegate. Moles supports static or non-virtual methods. Moles relies on the profiler from Pex.
You could inject the class (better: method/delegate) you use for DateTime.Now
in the class being tested. Have DateTime.Now
be a default value and only set it in testing to a dummy method that returns a constant value.
EDIT: What Blair Conrad said (he has some code to look at). Except, I tend to prefer delegates for this, as they don't clutter up your class hierarchy with stuff like IClock
...
I think creating a separate clock class for something simple like getting the current date is a bit overkill.
You can pass today's date as a parameter so you can input a different date in the test. This has the added benefit of making your code more flexible.
Simple answer: ditch System.DateTime :) Instead, use NodaTime and it's testing library: NodaTime.Testing.
Further reading: