212

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?

Kiquenet
  • 14,494
  • 35
  • 148
  • 243
Pedro
  • 11,514
  • 5
  • 27
  • 40
  • store some old value in the current time and compare it with datetime.now, as Unit testing uses fake data, you can easily do that, isn't it? – Prashant Lakhlani Mar 11 '10 at 14:35
  • 3
    Providing abstraction of current DateTime is useful not only for testing and debuging but also in production code - it depends on application needs. – Pavel Hodek Dec 18 '12 at 23:22
  • 1
    Don't use a static class to get the DateTime – Daniel Little Apr 12 '16 at 22:55
  • and another simple approach using VirtualTime below – Samuel Mar 20 '18 at 03:08
  • One option which might work and you're able to add an overload is to create an overload of the method which accepts the `DateTime`. This would be the one you test, the existing method would simply call the overload with `now`. – Phil Cooper Oct 17 '19 at 14:15

24 Answers24

256

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().

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • Thank you, this enables extreme flexibility and allows me to also control time in other situations than unit testing (since in unit testing mocking would be enough). – Pedro Mar 11 '10 at 14:45
  • 9
    In the case of an ambient context, even if you do tear down, how do you make your tests run in parallel? – Ilya Chernomordik Jul 21 '14 at 14:27
  • @IlyaChernomordik You *can* make a variation of Ambient Context that uses Thread Local Storage (TLS) instead of a static field, but I wouldn't recommend it, as it becomes much more complicated. Your question highlights why an injected abstraction is preferable. Chapter 4 in [my book](http://amzn.to/12p90MG) has more details about using TLS for Ambient Context. – Mark Seemann Jul 21 '14 at 15:43
  • @MarkSeemann Well, I have actually read your book (which is very good), but it did not cover the parallel unit testing case for the ambient context :) But if we will inject IDateTime, ILogger plus maybe some other technical dependencies, then there will be too many dependencies to inject and I cannot understand the best way of solving the issue. Ambient context would work - but it have those limitations – Ilya Chernomordik Jul 22 '14 at 10:41
  • 2
    @IlyaChernomordik You [shouldn't have to inject ILogger or other Cross-Cutting Concerns](http://stackoverflow.com/a/7906547/126014), so injecting a time provider is still the best option. – Mark Seemann Jul 22 '14 at 11:10
  • Is it better to drive the unit test the way you've described, as in TimeProvider.Current = timeMock.Object; or would it be more correct to have a constructor in the system under test that takes a TimeProvider parameter, and then have the test call that to inject the fake into it? The way you've done it here works great and is clean, I just worry that it requires the test framework to have knowledge of the SUT internals. – Mike K May 25 '15 at 19:57
  • 5
    @MikeK As the first sentence in my answer says: *The best strategy is to wrap the current time in an abstraction and inject that abstraction into the consumer.* Everything else in this answer is a second-best alternative. – Mark Seemann May 25 '15 at 20:04
  • That's also the best way if you plan on running tests asynchronously (in parallel). VS 2010 way; I haven't tried looking for it in newer versions: https://msdn.microsoft.com/en-us/library/ee921484(v=vs.100).aspx – ps2goat Sep 27 '16 at 21:22
  • 5
    Hi. I Noob. How does one prevent people accessing DateTime.UtcNow with this solution? It would be easy for someone to miss using the TimeProvider. Thus leading to bugs in testing? – Obbles May 10 '18 at 00:53
  • 3
    @Obbles Code reviews (or pair programming, which is a form of live code review). I suppose one could write a tool that scans the code base for `DateTime.UtcNow` and similar, but code reviews is a good idea anyway. – Mark Seemann May 10 '18 at 02:12
  • That'd work, although not everyone has the luxery :) Maybe the moles/fakes suggestion below might be a good for those in that circumstance. (I haven't got those working yet. I am using this method) – Obbles May 10 '18 at 11:57
  • The link "wrap the current time in an abstraction and inject that abstraction into the consumer." is broken :( – Sameer Shaik Apr 04 '19 at 13:28
  • 1
    What is `DefaultTimeProvider` here? – Koja Sep 27 '19 at 13:51
  • @Koja An implementation of the interface that uses the system clock. – Mark Seemann Sep 28 '19 at 14:21
  • Why isn't directly injecting the datetime through the parameters a good idea and injecting the provider is a better idea? – Ghosty Frosty Aug 11 '21 at 19:49
  • 1
    @GhostyFrosty FWIW, [these days I consider passing the time as a parameter the best design](https://blog.ploeh.dk/2020/02/24/discerning-and-maintaining-purity/#938b7dc2db644b6b94f6a484d65bb320). For higher-level integration tests, however, a polymorphic `Clock` dependency may still be useful. Here's an example (in a wider context): https://blog.ploeh.dk/2020/04/06/repeatable-execution-in-c – Mark Seemann Aug 12 '21 at 05:41
  • It would be worth adding a simple wrapper service that can be injected and mocked considering DI is so commonly used these days. It's also the simplest way to achieve it – Perbert Mar 17 '22 at 09:48
  • 1
    I actually refuse to believe the best answer is to change the implementation of the system under test just so I can run a test as OP wants. I think the real "best answer" is that it's time to admit that the tooling around testing in C# is not mature enough to even handle a simple (and very common) problem like this one. – fullStackChris May 09 '22 at 12:49
  • While injecting a date time provider works and is probably the "best" way to accomplish this, the fact that this is the best way to accomplish this is sub par. The date/time as an input to a particular object is so common that this forces devs to pollute a large number of constructors. Surely there could be a better way? – boylec1986 May 13 '22 at 17:14
68

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;
    }
}
Liam
  • 27,717
  • 28
  • 128
  • 190
  • 1
    Thank you, I like this functional aproach. Today (two years later) I am still using a modified version of the TimeProvider class (check the accepted answer), it works really nice. – Pedro Mar 28 '12 at 16:17
  • 10
    @crabCRUSHERclamCOLI: If you got the idea from http://ayende.com/blog/3408/dealing-with-time-in-tests , then it's A Good Thing to link to it. – Johann Gerell May 20 '12 at 10:35
  • Hey I think I saw the original idea there, I couldn't find the link when I posted this- Thanks! I added a little bit to the original code to make it more usable. – crabCRUSHERclamCOLLECTOR Jun 20 '12 at 17:40
  • 3
    This concept also works great for mocking Guid generation (public static Func NewGuid = () => Guid.NewGuid(); – Michael Whatcott Dec 06 '12 at 16:58
  • 2
    You can also add this useful method: public static void ResetDateTime(DateTime dateTimeNow) { var timespanDiff = TimeSpan.FromTicks(DateTime.Now.Ticks - dateTimeNow.Ticks); Now = () => DateTime.Now - timespanDiff; } – Pavel Hodek Dec 18 '12 at 23:16
  • What if I want to get some property on the fake DateTime object, for example `Year`, `Month` or `Day`? It says `'System.Func' does not contain a definition for 'Year'`. Not a good solution. – Gaui Aug 07 '14 at 17:25
  • 1
    You can easily get the Year, Month or Day. You need to remember that it's the Now function is wrapped in a Func<>.. You can do: SystemTime.Now().Year; – crabCRUSHERclamCOLLECTOR Aug 07 '14 at 21:05
  • Please review my answer http://stackoverflow.com/a/32519335/183020 I had problems winf entity framowirk using that approach – marcinn Sep 11 '15 at 08:51
  • 36
    very dangerous.This might affect other unit tests running in parallel. – Helen Araya Mar 30 '18 at 16:00
  • This solution could lead to strange behavior when running tests in parallel. This kind of problems are hard to find - tests could success locally, but fail on some continuous integration machine. You might want to use [ThreadStatic] in this case, or solution from accepted answer. – Jonatan Dragon Jun 28 '18 at 11:47
  • ThreadStatic would still not work, when single test runs two different threads. Better use accepted answer in this case. – Jonatan Dragon Jun 28 '18 at 11:55
  • Perfect for my project. Dates are isolated functionality, not integral to business logic. – Fred Haslam Aug 06 '23 at 21:19
25

You have some options for doing it:

  1. 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.

  2. Use Typemock Isolator, it can fake DateTime.Now and won't require you to change the code under test.

  3. 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

Elisha
  • 23,310
  • 6
  • 60
  • 75
25

Moles:

[Test]  
public void TestOfDateTime()  
{  
      var firstValue = DateTime.Now;
      MDateTime.NowGet = () => new DateTime(2000,1,1);
      var secondValue = DateTime.Now;
      Assert(firstValue > secondValue); // would be false if 'moleing' failed
}

Disclaimer - I work on Moles

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Peli
  • 2,465
  • 16
  • 17
  • 1
    unfortunately doesn't work with nunit and resharper. – odyth Nov 01 '15 at 03:28
  • 3
    Looks like Moles is now unsupported, replaced with Fakes https://msdn.microsoft.com/en-us/library/hh549175%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396, no doubt MS will discontinue that too soon – danio Jun 30 '17 at 10:28
18

Add a fake assembly for System (right click on System reference=>Add fake assembly).

And write into your test method:

using (ShimsContext.Create())
{
   System.Fakes.ShimDateTime.NowGet = () => new DateTime(2014, 3, 10);
   MethodThatUsesDateTimeNow();
}
Liam
  • 27,717
  • 28
  • 128
  • 190
dave
  • 2,291
  • 3
  • 19
  • 25
  • if you have access to Vs Premium or ultimate This is by far the easiest / fastest way to do it. – Rugdr Apr 14 '15 at 13:12
  • 2
    Visual Studio Enterprise is required. More details how to create and use [Microsoft fakers](https://learn.microsoft.com/en-us/visualstudio/test/isolating-code-under-test-with-microsoft-fakes?view=vs-2019) – Tatranskymedved May 05 '21 at 09:43
  • This doesn't work in Rider! – Shilan Aug 03 '22 at 12:31
9

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();
        }
    }
Nir
  • 1,836
  • 23
  • 26
  • 2
    I like this answer. From what I've gathered though, this might be eye-brow raising in the C# world where there's more of a focus on classes/objects. Either way, I prefer this because it's really simple and clear to me what's happening. – pseudoramble May 25 '20 at 14:24
8

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;
            }
        }
    }
marcinn
  • 1,879
  • 2
  • 22
  • 46
  • I'm guessing by EF you mean Entity Framework? What does the object you're using SystemTime on look like? My guess is you have a reference to SystemTime on the actual entity, instead you should use a regular DateTime object on your entity and set it using SystemTime wherever it makes sense in your application – crabCRUSHERclamCOLLECTOR Sep 26 '15 at 21:03
  • 1
    Yes I have tested it when creating linq query and EntityFramework6 and referencing in that query UtcNow from SystemTime. There was exception as described. After changing implementation it works well. – marcinn Oct 20 '15 at 21:26
  • I love this solution! Great! – mirind4 Feb 28 '20 at 09:43
8

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);
});
persianLife
  • 1,206
  • 3
  • 17
  • 22
6

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();
}
Henk van Boeijen
  • 7,357
  • 6
  • 32
  • 42
  • 1
    +! Thread local should avoid issues with parallel test execution and multiple tests potentially overriding the current `Now` instance. – Hux Feb 23 '17 at 11:27
  • 1
    Tried to use this but had an issue across threads so have gone with a similar principal but using `AsyncLocal` rather than `ThreadLocal` – rrrr-o Aug 30 '18 at 15:04
  • @rrrr: can you explain the issue you had? – Henk van Boeijen Aug 30 '18 at 15:45
  • @HenkvanBoeijen Sure, we ran into issues when the time was set and then we were awaiting an async method. `Console.WriteLine(SystemClock.Now); SystemClock.Set(new DateTime(2017, 01, 01)); Console.WriteLine(SystemClock.Now); await Task.Delay(1000); Console.WriteLine(SystemClock.Now);` – rrrr-o Aug 31 '18 at 09:51
  • @HenkvanBoeijen I've added an answer with what I ended up using [link](https://stackoverflow.com/a/52100319/254156) – rrrr-o Aug 31 '18 at 12:24
3

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.

Bobby Cannon
  • 6,665
  • 8
  • 33
  • 46
  • 2
    BTW, this only works with VS2010. I was upset when I found that Moles is now Fakes for VS2012 and it's only available for Premium and Ultimate Visual Studios. No Fakes for VS 2012 Professional. So I never got to actually use this. :( – Bobby Cannon Sep 15 '13 at 14:23
3

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.

sara
  • 3,521
  • 14
  • 34
  • How can you then override the virtual method in test class? Test class doesn't inherit the sut class. – Shilan Aug 03 '22 at 11:31
3

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

Mino
  • 305
  • 2
  • 12
3

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

rrrr-o
  • 2,447
  • 2
  • 24
  • 52
3

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.

Kevin Brydon
  • 12,524
  • 8
  • 46
  • 76
3

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))
smonff
  • 3,399
  • 3
  • 36
  • 46
Dave Black
  • 7,305
  • 2
  • 52
  • 41
1

Mock Objects.

A mock DateTime that returns a Now that's appropriate for your test.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
1

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:

https://github.com/VirtualTime/VirtualTime/blob/master/VirtualTimeLib.Tests/when_virtual_time_is_used.cs

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);
}
Samuel
  • 1,295
  • 16
  • 21
  • There is also a good read about testing code that depends on DateTime by Ayende here https://ayende.com/blog/3408/dealing-with-time-in-tests – Samuel Mar 20 '18 at 00:20
0

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

Dipon Roy
  • 396
  • 1
  • 4
  • 18
0

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;
        }
    }
}
Stefc
  • 73
  • 6
0

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>.

How to use

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());
    }
}

How to register

Autofac

builder.RegisterInstance<Func<DateTimeOffset>>(() => DateTimeOffset.Now);

(For future editors: append your cases here).

How to unit test

public void MakeIllustratingTuple_WhenCalled_FillsCreatedAt()
{
    DateTimeOffset expected = CreateRandomDateTimeOffset();
    DateTimeOffset StubNow() => expected;
    var thing = new ThingThatNeedsTimeProvider(StubNow);

    var (_, actual) = thing.MakeIllustratingTuple();

    Assert.AreEqual(expected, actual);
}
Mark Shevchenko
  • 7,937
  • 1
  • 25
  • 29
0

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)
        {

        }

    }
Mehmet
  • 739
  • 1
  • 6
  • 17
0

.NET 8 solution (build in .NET 8 base class library)

With .NET 8 (currently in preview) this is build in the class library!

There will be a TimeProvider class which looks like the class provider with the answer of Mark Seemann

So with .NET 8 there is no need to create your own class.

Usage

Inject TimeProvider in your object and use .GetUtcNow() or .GetLocalNow()

Register in TimeProvider.System for your code (for example in Startup.cs or Program.cs):

services.AddSingleton(TimeProvider.System);

In the tests you could Mock the TimeProvider class, for example with Moq

var timeProviderMock = new Mock<TimeProvider>();
timeProviderMock.Setup(t => t.GetLocalNow).Returns(new DateTime(2010, 3, 11));
var timeProvider = timeProviderMock.Object

Info

See also API to provide the current system time #36617

Please note, you need .Net 8.0.0-preview.2 or later, See For .net 8, how can I fix The type or namespace name 'TimeProvider' could not be found?

Julian
  • 33,915
  • 22
  • 119
  • 174
0

I have seen a lot of variations of creating mockable methods. Here is yet another. This is probably not performant, but speed is not essential to my application. The internal method can be overridden in a test environment:

public class TimeTools {

    public static string DateNowTimestamp(){
        return UtcNow().ToString("u").Replace(" ","T");
    }

    public static string DateNowFilekey(){
        return UtcNow().ToString("yyyyMMdd_HHmmss");
    }

    public static long DateNowEpochSeconds(){
        return new DateTimeOffset(UtcNow()).ToUnixTimeSeconds();
    }

    internal static Func<DateTime> UtcNow { get; set; } = () => DateTime.UtcNow;

}

Bon Apetit!

Fred Haslam
  • 8,873
  • 5
  • 31
  • 31
-2

The following code works for me:

  bizDeedMock.Verify(p => p.SetDeed(It.Is<DsPostList>(x => x.PostLists[0].registerDate.Year == DateTime.Now.Year)));
            bizDeedMock.Verify(p => p.SetDeed(It.Is<DsPostList>(x => x.PostLists[0].registerDate.Month == DateTime.Now.Month)));
            bizDeedMock.Verify(p => p.SetDeed(It.Is<DsPostList>(x => x.PostLists[0].registerDate.Day == DateTime.Now.Day)));
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
stefan
  • 11
  • 3