I have business logic that does not perform certain functions on Saturday or Sunday. I want my unit tests to verify that these functions are performed, but the tests will f
Is it possible/advisable to try and mock the date?
Yes, not only that it is advisable but it is the only way to reliably unit test your code in isolation. Suppose that you wanted to test the following (meaningless) method:
public bool Foo()
{
return (DateTime.Now.DayOfWeek == DayOfWeek.Sunday);
}
It's more than obvious that you can't test it because it relies on a static method (the static Now property to be more precise). It's clear that components which are tightly coupled like this cannot be unit tested in isolation.
Now consider this improvement (separation of concerns with constructor DI):
private readonly Func<DateTime> _nowProvider;
public SomeClass(Func<DateTime> nowProvider)
{
_nowProvider = nowProvider;
}
public bool Foo()
{
return (_nowProvider().DayOfWeek == DayOfWeek.Sunday);
}
Now that's much better and easier to unit test. SomeClass
no longer depends on a non-deterministic date. In the real application you would obviously instantiate SomeClass
like this:
var s = new SomeClass(() => DateTime.Now);
s.Foo();
and in your unit test you will mock it so that you can verify both cases:
var subjectUnderTest = new SomeClass(() => new DateTime(2011, 1, 3));
var actual = subjectUnderTest.Foo();
// assertions, ...
You should create an abstraction over the system clock, as you should create abstractions over other system resources and external resources to be able to write RTM unit tests.
An abstraction over the system clock is pretty simple and could look like this:
public interface ISystemClock
{
DateTime Now { get; }
}
Classes in your application that depend on the system clock should than typically have an ISystemClock
as constructor argument. For unit testing scenario's you can use an ISystemClock
implementation that looks like this:
public class FakeSystemClock : ISystemClock
{
// Note the setter.
public DateTime Now { get; set; }
}
Now you can use this fake clock in your unit tests like this:
[TestMethod]
[ExpectedException(typeof(InvalidOperationException),
"Service should throw an exception when called on saturday.")]
public void DoSomething_WhenCalledOnSaturday_ThrowsException()
{
// Arrange
var saturday = new DateTime(2011, 1, 1);
Assert.AreEqual(saturday.DayOfWeek, DayOfWeek.Saturday,
"Test setup fail");
var clock = new FakeSystemClock() { Now = saturday };
var service = new Service(clock);
// Act
service.DoSomething();
}
In your application project you can define an ISystemClock
implementation that actually uses the system clock. Using the given ISystemClock
definition, it will look like this:
public class RealSystemClock : ISystemClock
{
public DateTime Now => DateTime.Now;
}
When you use a DI container, you can configure it to wire up your types and automatically inject instances of RealSystemClock
when a constructor specifies a ISystemClock
argument.
btw. While you could use Func<DateTime>
delegates to do the trick, defining an interface for this is much more explicit and much more readable to other developers. Besides that, wiring everything in a DI container would be much easier, because it's so easy to end up with multiple Func<DateTime>
dependencies that all do different things than "give me the current local time".
I hope this helps.