When writing unit tests, you probably met with the question of how to test the method, the calculation of which is dependent on DateTime.Now. DateTime.Now always returns a new value according to the current time, so testing this method is not directly possible.

It is certainly a number of ways this problem can be solved. The most frequent recommendations are however two:

  1. Methods that calculation is depends on the current date and time should get this date as an input parameter. This means that you will not use DateTime.Now in the body of the method, but need send a DateTime type parameter sent to you by your method. Thus, send the test date what you need. Of course, not always it is possible and it is not always desirable.

  2. Do not use directly DateTime.Now, but have custom DateTime Provider

Custom DateTimeProvider

Under own DateTimeProvider think custom class, which we will ask for the current date and time. And it will be possible inject the current date. An example of this class:

public class DateTimeProvider : IDisposable 
{
    private static AsyncLocal<DateTime?> _injectedDateTime = new AsyncLocal<DateTime?>(); 
 
    private DateTimeProvider() 
    { 
    } 
 
    /// <summary> 
    /// Gets DateTime now. 
    /// </summary> 
    /// <value> 
    /// The DateTime now. 
    /// </value> 
    public static DateTime Now => _injectedDateTime.Value ?? DateTime.Now;
 
    /// <summary> 
    /// Injects the actual date time. 
    /// </summary> 
    /// <param name="actualDateTime">The actual date time.</param> 
    public static IDisposable InjectActualDateTime(DateTime actualDateTime) 
    { 
        _injectedDateTime.Value = actualDateTime; 
 
        return new DateTimeProvider(); 
    } 
 
    public void Dispose() 
    { 
        _injectedDateTime.Value = null; 
    } 
} 

The common usage in the method is the same as when you use the DateTime.

private void MakeTransaction(Transaction transaction) 
{ 
    transaction.TransactionDate = DateTimeProvider.Now; 
    _transactions.Add(transaction); 
}

The class implements IDisposable and has a static factory method InjectActualDateTime that you can use to insert a fake value. If the class has injected a fake date, Now property returns just this. The use own date in test:

[TestClass] 
public class BankAccountShould 
{ 
    [TestMethod] 
    public void SetCorrectDateTimeToTransaction() 
    { 
        var expectedDateTime = new DateTime(2016, 4, 6); 
 
        using (DateTimeProvider.InjectActualDateTime(expectedDateTime)) 
        { 
            var bankAccount = new BankAccount(); 
 
            bankAccount.DepositMoney(600); 
 
            var lastTransaction = bankAccount.Transactions.Last(); 
 
            Assert.AreEquel(expectedDateTime, bankAccount.Transactions[0].TransactionDate); 
        } 
    } 
} 

See demo project.