I have some unit tests that expects the 'current time' to be different than DateTime.Now and I don't want to change the computer's time, obviously.
What's the best strategy to achieve this?
The best strategy is to wrap the current time in an abstraction and inject that abstraction into the consumer.
Alternatively, you can also define a time abstraction as an Ambient Context:
public abstract class TimeProvider
{
private static TimeProvider current =
DefaultTimeProvider.Instance;
public static TimeProvider Current
{
get { return TimeProvider.current; }
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
TimeProvider.current = value;
}
}
public abstract DateTime UtcNow { get; }
public static void ResetToDefault()
{
TimeProvider.current = DefaultTimeProvider.Instance;
}
}
This will enable you to consume it like this:
var now = TimeProvider.Current.UtcNow;
In a unit test, you can replace TimeProvider.Current
with a Test Double/Mock object. Example using Moq:
var timeMock = new Mock<TimeProvider>();
timeMock.SetupGet(tp => tp.UtcNow).Returns(new DateTime(2010, 3, 11));
TimeProvider.Current = timeMock.Object;
However, when unit testing with static state, always remember to tear down your fixture by calling TimeProvider.ResetToDefault()
.
These are all good answers, this is what I did on a different project:
Usage:
Get Today's REAL date Time
var today = SystemTime.Now().Date;
Instead of using DateTime.Now, you need to use SystemTime.Now()
... It's not hard change but this solution might not be ideal for all projects.
Time Traveling (Lets go 5 years in the future)
SystemTime.SetDateTime(today.AddYears(5));
Get Our Fake "today" (will be 5 years from 'today')
var fakeToday = SystemTime.Now().Date;
Reset the date
SystemTime.ResetDateTime();
/// <summary>
/// Used for getting DateTime.Now(), time is changeable for unit testing
/// </summary>
public static class SystemTime
{
/// <summary> Normally this is a pass-through to DateTime.Now, but it can be overridden with SetDateTime( .. ) for testing or debugging.
/// </summary>
public static Func<DateTime> Now = () => DateTime.Now;
/// <summary> Set time to return when SystemTime.Now() is called.
/// </summary>
public static void SetDateTime(DateTime dateTimeNow)
{
Now = () => dateTimeNow;
}
/// <summary> Resets SystemTime.Now() to return DateTime.Now.
/// </summary>
public static void ResetDateTime()
{
Now = () => DateTime.Now;
}
}
You have some options for doing it:
Use mocking framework and use a DateTimeService (Implement a small wrapper class and inject it to production code). The wrapper implementation will access DateTime and in the tests you'll be able to mock the wrapper class.
Use Typemock Isolator, it can fake DateTime.Now and won't require you to change the code under test.
Use Moles, it can also fake DateTime.Now and won't require change in production code.
Some examples:
Wrapper class using Moq:
[Test]
public void TestOfDateTime()
{
var mock = new Mock<IDateTime>();
mock.Setup(fake => fake.Now)
.Returns(new DateTime(2000, 1, 1));
var result = new UnderTest(mock.Object).CalculateSomethingBasedOnDate();
}
public class DateTimeWrapper : IDateTime
{
public DateTime Now { get { return DateTime.Now; } }
}
Faking DateTime directly using Isolator:
[Test]
public void TestOfDateTime()
{
Isolate.WhenCalled(() => DateTime.Now).WillReturn(new DateTime(2000, 1, 1));
var result = new UnderTest().CalculateSomethingBasedOnDate();
}
Disclaimer - I work at Typemock
Regarding to @crabcrusherclamcollector answer there is issue when using that approach in EF queries (System.NotSupportedException: The LINQ expression node type 'Invoke' is not supported in LINQ to Entities). I modified implementation to that:
public static class SystemTime
{
private static Func<DateTime> UtcNowFunc = () => DateTime.UtcNow;
public static void SetDateTime(DateTime dateTimeNow)
{
UtcNowFunc = () => dateTimeNow;
}
public static void ResetDateTime()
{
UtcNowFunc = () => DateTime.UtcNow;
}
public static DateTime UtcNow
{
get
{
DateTime now = UtcNowFunc.Invoke();
return now;
}
}
}
To test a code that depends on the System.DateTime
, the system.dll
must be mocked.
There are two framework that I know of that does this. Microsoft fakes and Smocks.
Microsoft fakes require visual studio 2012 ultimatum and works straight out of the compton.
Smocks is an open source and very easy to use. It can be downloaded using NuGet.
The following shows a mock of System.DateTime
:
Smock.Run(context =>
{
context.Setup(() => DateTime.Now).Returns(new DateTime(2000, 1, 1));
// Outputs "2000"
Console.WriteLine(DateTime.Now.Year);
});
A thread safe SystemClock
using ThreadLocal<T>
works great for me.
ThreadLocal<T>
is available in the .Net Framework v4.0 and higher.
/// <summary>
/// Provides access to system time while allowing it to be set to a fixed <see cref="DateTime"/> value.
/// </summary>
/// <remarks>
/// This class is thread safe.
/// </remarks>
public static class SystemClock
{
private static readonly ThreadLocal<Func<DateTime>> _getTime =
new ThreadLocal<Func<DateTime>>(() => () => DateTime.Now);
/// <inheritdoc cref="DateTime.Today"/>
public static DateTime Today
{
get { return _getTime.Value().Date; }
}
/// <inheritdoc cref="DateTime.Now"/>
public static DateTime Now
{
get { return _getTime.Value(); }
}
/// <inheritdoc cref="DateTime.UtcNow"/>
public static DateTime UtcNow
{
get { return _getTime.Value().ToUniversalTime(); }
}
/// <summary>
/// Sets a fixed (deterministic) time for the current thread to return by <see cref="SystemClock"/>.
/// </summary>
public static void Set(DateTime time)
{
if (time.Kind != DateTimeKind.Local)
time = time.ToLocalTime();
_getTime.Value = () => time;
}
/// <summary>
/// Resets <see cref="SystemClock"/> to return the current <see cref="DateTime.Now"/>.
/// </summary>
public static void Reset()
{
_getTime.Value = () => DateTime.Now;
}
}
Usage example:
[TestMethod]
public void Today()
{
SystemClock.Set(new DateTime(2015, 4, 3));
DateTime expectedDay = new DateTime(2015, 4, 2);
DateTime yesterday = SystemClock.Today.AddDays(-1D);
Assert.AreEqual(expectedDay, yesterday);
SystemClock.Reset();
}
I ran into this same issue but found a research project from Microsoft that solves this issue.
http://research.microsoft.com/en-us/projects/moles/
Moles is a lightweight framework for test stubs and detours in .NET that is based on delegates. Moles may be used to detour any .NET method, including non-virtual/static methods in sealed types
// Let's detour DateTime.Now
MDateTime.NowGet = () => new DateTime(2000,1, 1);
if (DateTime.Now == new DateTime(2000, 1, 1);
{
throw new Exception("Wahoo we did it!");
}
The sample code was modified from the original.
I had done what other suggested and abstracted the DateTime into a provider. It just felt wrong and I felt like it was too much just for testing. I'm going to implement this into my personal project this evening.
One special note on mocking DateTime.Now
with TypeMock...
The value of DateTime.Now
must be placed into a variable for this to be mocked properly. For example:
This does not work:
if ((DateTime.Now - message.TimeOpened.Value) > new TimeSpan(1, 0, 0))
However, this does:
var currentDateTime = DateTime.Now;
if ((currentDateTime - message.TimeOpened.Value) > new TimeSpan(1, 0, 0))
You can change the class you are testing to use a Func<DateTime>
which will be passed through it's constructor parameters, so when you create instance of the class in real code, you can pass () => DateTime.UtcNow
to the Func<DateTime>
parameter, and on the test, you can pass the time you wish to test.
For example:
[TestMethod]
public void MyTestMethod()
{
var instance = new MyClass(() => DateTime.MinValue);
Assert.AreEqual(instance.MyMethod(), DateTime.MinValue);
}
public void RealWorldInitialization()
{
new MyClass(() => DateTime.UtcNow);
}
class MyClass
{
private readonly Func<DateTime> _utcTimeNow;
public MyClass(Func<DateTime> UtcTimeNow)
{
_utcTimeNow = UtcTimeNow;
}
public DateTime MyMethod()
{
return _utcTimeNow();
}
}
I'm surprised no one has suggested one of the most obvious ways to go:
public class TimeDependentClass
{
public void TimeDependentMethod(DateTime someTime)
{
if (GetCurrentTime() > someTime) DoSomething();
}
protected virtual DateTime GetCurrentTime()
{
return DateTime.Now; // or UtcNow
}
}
Then you can simply override this method in your test double.
I also kind of like injecting a TimeProvider
class in some cases, but for others, this is more than enough. I'd probably favor the TimeProvider
version if you need to reuse this in several classes though.
EDIT: For anyone interested, this is called adding a "seam" to your class, a point where you can hook in to it's behavior to modify it (for testing purposes or otherwise) without actually having to change the code in the class.
Good practice is, when DateTimeProvider implements IDisposable.
public class DateTimeProvider : IDisposable
{
[ThreadStatic]
private static DateTime? _injectedDateTime;
private DateTimeProvider()
{
}
/// <summary>
/// Gets DateTime now.
/// </summary>
/// <value>
/// The DateTime now.
/// </value>
public static DateTime Now
{
get
{
return _injectedDateTime ?? DateTime.Now;
}
}
/// <summary>
/// Injects the actual date time.
/// </summary>
/// <param name="actualDateTime">The actual date time.</param>
public static IDisposable InjectActualDateTime(DateTime actualDateTime)
{
_injectedDateTime = actualDateTime;
return new DateTimeProvider();
}
public void Dispose()
{
_injectedDateTime = null;
}
}
Next, you can inject your fake DateTime for unit tests
using (var date = DateTimeProvider.InjectActualDateTime(expectedDateTime))
{
var bankAccount = new BankAccount();
bankAccount.DepositMoney(600);
var lastTransaction = bankAccount.Transactions.Last();
Assert.IsTrue(expectedDateTime.Equals(bankAccount.Transactions[0].TransactionDate));
}
See example Example of DateTimeProvider
One clean way to do this is to inject VirtualTime. It allows you to control time. First install VirtualTime
Install-Package VirtualTime
That allows to, for example, make time that moves 5 times faster on all calls to DateTime.Now or UtcNow
var DateTime = DateTime.Now.ToVirtualTime(5);
To make time move slower , eg 5 times slower do
var DateTime = DateTime.Now.ToVirtualTime(0.5);
To make time stand still do
var DateTime = DateTime.Now.ToVirtualTime(0);
Moving backwards in time is not tested yet
Here are a sample test:
[TestMethod]
public void it_should_make_time_move_faster()
{
int speedOfTimePerMs = 1000;
int timeToPassMs = 3000;
int expectedElapsedVirtualTime = speedOfTimePerMs * timeToPassMs;
DateTime whenTimeStarts = DateTime.Now;
ITime time = whenTimeStarts.ToVirtualTime(speedOfTimePerMs);
Thread.Sleep(timeToPassMs);
DateTime expectedTime = DateTime.Now.AddMilliseconds(expectedElapsedVirtualTime - timeToPassMs);
DateTime virtualTime = time.Now;
Assert.IsTrue(TestHelper.AreEqualWithinMarginOfError(expectedTime, virtualTime, MarginOfErrorMs));
}
You can check out more tests here:
What DateTime.Now.ToVirtualTime extension gives you is an instance of ITime which you pass to a method / class that depends on ITime. some DateTime.Now.ToVirtualTime is setup in the DI container of your choice
Here is another example injecting into a class contrustor
public class AlarmClock
{
private ITime DateTime;
public AlarmClock(ITime dateTime, int numberOfHours)
{
DateTime = dateTime;
SetTime = DateTime.UtcNow.AddHours(numberOfHours);
Task.Run(() =>
{
while (!IsAlarmOn)
{
IsAlarmOn = (SetTime - DateTime.UtcNow).TotalMilliseconds < 0;
}
});
}
public DateTime SetTime { get; set; }
public bool IsAlarmOn { get; set; }
}
[TestMethod]
public void it_can_be_injected_as_a_dependency()
{
//virtual time has to be 1000*3.75 faster to get to an hour
//in 1000 ms real time
var dateTime = DateTime.Now.ToVirtualTime(1000 * 3.75);
var numberOfHoursBeforeAlarmSounds = 1;
var alarmClock = new AlarmClock(dateTime, numberOfHoursBeforeAlarmSounds);
Assert.IsFalse(alarmClock.IsAlarmOn);
System.Threading.Thread.Sleep(1000);
Assert.IsTrue(alarmClock.IsAlarmOn);
}
We were using a static SystemTime object, but ran into problems running parallel unit tests. I attempted to use Henk van Boeijen's solution but had problems across spawned asynchronous threads, ended up using using AsyncLocal in a manner similar to this below:
public static class Clock
{
private static Func<DateTime> _utcNow = () => DateTime.UtcNow;
static AsyncLocal<Func<DateTime>> _override = new AsyncLocal<Func<DateTime>>();
public static DateTime UtcNow => (_override.Value ?? _utcNow)();
public static void Set(Func<DateTime> func)
{
_override.Value = func;
}
public static void Reset()
{
_override.Value = null;
}
}
Sourced from https://gist.github.com/CraftyFella/42f459f7687b0b8b268fc311e6b4af08
An old question, but still valid.
My approach is to create a new interface and class to wrap the System.DateTime.Now
call
public interface INow
{
DateTime Execute();
}
public sealed class Now : INow
{
public DateTime Execute()
{
return DateTime.Now
}
}
This interface can be injected into any class that needs to get the current date and time. In this example, I have a class that adds a timespan to the current date and time (a unit testable System.DateTime.Now.Add(TimeSpan))
public interface IAddTimeSpanToCurrentDateAndTime
{
DateTime Execute(TimeSpan input);
}
public class AddTimeSpanToCurrentDateAndTime : IAddTimeSpanToCurrentDateAndTime
{
private readonly INow _now;
public AddTimeSpanToCurrentDateAndTime(INow now)
{
this._now = now;
}
public DateTime Execute(TimeSpan input)
{
var currentDateAndTime = this._now.Execute();
return currentDateAndTime.Add(input);
}
}
And tests can be written to ensure that it functions correctly. I'm using NUnit and Moq but any test framework will do
public class Execute
{
private Moq.Mock<INow> _nowMock;
private AddTimeSpanToCurrentDateAndTime _systemUnderTest;
[SetUp]
public void Initialize()
{
this._nowMock = new Moq.Mock<INow>(Moq.MockBehavior.Strict);
this._systemUnderTest = AddTimeSpanToCurrentDateAndTime(
this._nowMock.Object);
}
[Test]
public void AddTimeSpanToCurrentDateAndTimeExecute0001()
{
// arrange
var input = new TimeSpan(911252);
// arrange : mocks
this._nowMock
.Setup(a => a.Execute())
.Returns(new DateTime(348756););
// arrange : expected
var expected = new DateTime(911252 + 348756);
// act
var actual = this._systemUnderTest.Execute(input).Result;
// assert
Assert.Equals(actual, expected);
}
}
This pattern will work for any functions which depend on external factors, like System.Random.Next()
, System.DateTime.Now.UtcNow
, System.Guid.NewGuid()
etc.
See https://loadlimited.visualstudio.com/Stamina/_git/Stamina.Core for further examples or get the https://www.nuget.org/packages/Stamina.Core nuget package.
I got same problem, but i was thinking we should not use the set datetime things on the same class. because it could lead to misuse one day. so i have used the provider like
public class DateTimeProvider
{
protected static DateTime? DateTimeNow;
protected static DateTime? DateTimeUtcNow;
public DateTime Now
{
get
{
return DateTimeNow ?? System.DateTime.Now;
}
}
public DateTime UtcNow
{
get
{
return DateTimeUtcNow ?? System.DateTime.UtcNow;
}
}
public static DateTimeProvider DateTime
{
get
{
return new DateTimeProvider();
}
}
protected DateTimeProvider()
{
}
}
For tests, at test project made a helper which will deal with set things,
public class MockDateTimeProvider : DateTimeProvider
{
public static void SetNow(DateTime now)
{
DateTimeNow = now;
}
public static void SetUtcNow(DateTime utc)
{
DateTimeUtcNow = utc;
}
public static void RestoreAsDefault()
{
DateTimeNow = null;
DateTimeUtcNow = null;
}
}
on code
var dateTimeNow = DateTimeProvider.DateTime.Now //not DateTime.Now
var dateTimeUtcNow = DateTimeProvider.DateTime.UtcNow //not DateTime.UtcNow
and on tests
[Test]
public void Mocked_Now()
{
DateTime now = DateTime.Now;
MockDateTimeProvider.SetNow(now); //set to mock
Assert.AreEqual(now, DateTimeProvider.DateTime.Now);
Assert.AreNotEqual(now, DateTimeProvider.DateTime.UtcNow);
}
[Test]
public void Mocked_UtcNow()
{
DateTime utcNow = DateTime.UtcNow;
MockDateTimeProvider.SetUtcNow(utcNow); //set to mock
Assert.AreEqual(utcNow, DateTimeProvider.DateTime.UtcNow);
Assert.AreNotEqual(utcNow, DateTimeProvider.DateTime.Now);
}
But need to remember one thing, sometime the real DateTime and provider's DateTime doesn't act same
[Test]
public void Now()
{
Assert.AreEqual(DateTime.Now.Kind, DateTimeProvider.DateTime.Now.Kind);
Assert.LessOrEqual(DateTime.Now, DateTimeProvider.DateTime.Now);
Assert.LessOrEqual(DateTimeProvider.DateTime.Now - DateTime.Now, TimeSpan.FromMilliseconds(1));
}
I assumed the deference would be maximum TimeSpan.FromMilliseconds(0.00002). But most of the time it's even less
Find the sample at MockSamples
Here is my anwer of this question. I combine the 'Ambient Context' pattern with IDisposable. So you can use the DateTimeProvider.Current in your normal program code and in the test you override the scope with a using statement.
using System;
using System.Collections.Immutable;
namespace ambientcontext {
public abstract class DateTimeProvider : IDisposable
{
private static ImmutableStack<DateTimeProvider> stack = ImmutableStack<DateTimeProvider>.Empty.Push(new DefaultDateTimeProvider());
protected DateTimeProvider()
{
if (this.GetType() != typeof(DefaultDateTimeProvider))
stack = stack.Push(this);
}
public static DateTimeProvider Current => stack.Peek();
public abstract DateTime Today { get; }
public abstract DateTime Now {get; }
public void Dispose()
{
if (this.GetType() != typeof(DefaultDateTimeProvider))
stack = stack.Pop();
}
// Not visible Default Implementation
private class DefaultDateTimeProvider : DateTimeProvider {
public override DateTime Today => DateTime.Today;
public override DateTime Now => DateTime.Now;
}
}
}
Here is how to use the above DateTimeProvider inside a Unit-Test
using System;
using Xunit;
namespace ambientcontext
{
public class TestDateTimeProvider
{
[Fact]
public void TestDateTime()
{
var actual = DateTimeProvider.Current.Today;
var expected = DateTime.Today;
Assert.Equal<DateTime>(expected, actual);
using (new MyDateTimeProvider(new DateTime(2012,12,21)))
{
Assert.Equal(2012, DateTimeProvider.Current.Today.Year);
using (new MyDateTimeProvider(new DateTime(1984,4,4)))
{
Assert.Equal(1984, DateTimeProvider.Current.Today.Year);
}
Assert.Equal(2012, DateTimeProvider.Current.Today.Year);
}
// Fall-Back to Default DateTimeProvider
Assert.Equal<int>(expected.Year, DateTimeProvider.Current.Today.Year);
}
private class MyDateTimeProvider : DateTimeProvider
{
private readonly DateTime dateTime;
public MyDateTimeProvider(DateTime dateTime):base()
{
this.dateTime = dateTime;
}
public override DateTime Today => this.dateTime.Date;
public override DateTime Now => this.dateTime;
}
}
}
Using ITimeProvider
we were forced to take it into special shared common project that must be referenced from the rest of other projects. But this complicated the control of dependencies.
We searched for the ITimeProvider
in the .NET framework. We searched for the NuGet package, and found one that can't work with DateTimeOffset
.
So we came up with our own solution, which depends only on the types of the standard library. We're using an instance of Func<DateTimeOffset>
.
public class ThingThatNeedsTimeProvider
{
private readonly Func<DateTimeOffset> now;
private int nextId;
public ThingThatNeedsTimeProvider(Func<DateTimeOffset> now)
{
this.now = now;
this.nextId = 1;
}
public (int Id, DateTimeOffset CreatedAt) MakeIllustratingTuple()
{
return (nextId++, now());
}
}
Autofac
builder.RegisterInstance<Func<DateTimeOffset>>(() => DateTimeOffset.Now);
(For future editors: append your cases here).
public void MakeIllustratingTuple_WhenCalled_FillsCreatedAt()
{
DateTimeOffset expected = CreateRandomDateTimeOffset();
DateTimeOffset StubNow() => expected;
var thing = new ThingThatNeedsTimeProvider(StubNow);
var (_, actual) = thing.MakeIllustratingTuple();
Assert.AreEqual(expected, actual);
}
Maybe less Professional but simpler solution could be make a DateTime parameter at consumer method.For example instead of make method like SampleMethod , make SampleMethod1 with parameter.Testing of SampleMethod1 is easier
public void SampleMethod()
{
DateTime anotherDateTime = DateTime.Today.AddDays(-10);
if ((DateTime.Now-anotherDateTime).TotalDays>10)
{
}
}
public void SampleMethod1(DateTime dateTimeNow)
{
DateTime anotherDateTime = DateTime.Today.AddDays(-10);
if ((dateTimeNow - anotherDateTime).TotalDays > 10)
{
}
}
DateTime
. This would be the one you test, the existing method would simply call the overload withnow
. – Phil Cooper