Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 497 Vote(s) - 3.49 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Unit Testing: DateTime.Now

#1
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?
Reply

#2
Mock Objects.

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

#3
*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*
Reply

#4
I ran into this same issue but found a research project from Microsoft that solves this issue.

[To see links please register here]


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

#5
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][1], it can [fake DateTime.Now][2] and won't require you to change the code under test.


3. Use [Moles][3], it can also [fake DateTime.Now][4] 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*


[1]:

[To see links please register here]

[2]:

[To see links please register here]

[3]:

[To see links please register here]

[4]:

[To see links please register here]

Reply

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



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through