Is stubbing time overkill? If it is required for your tests to be reliable, I would say no, it’s not overkill. In this test I will discuss why and how to stub time to make your coded tests break free from the constraints of time. Wish it was as easy to do outside of the code world as well…

I use the term stub here. I usually make the distinction between mocks and stubs, in that a stub simply returns a hard-coded response, while the mock will also register the interaction as such, so that the test can verify that the mock was indeed invoked.

An important part of writing tests is to always be aware of what it is that you are actually testing. One side effect of this is that you will need to fake anything that is not currently under test. For instance, if you have code that processes data from some data store, your test should fake the data store and feed hard-coded input to the processing code. This will give your test code at least three advantages:

  • It does not require extra dependencies on the data layer
  • It makes the test reliable since you always execute it using the exact same input
  • The tests will take less time to run

If you run your test on input that can change over time, the test may fail for two different reasons:

  • there is something wrong with the code that you are testing
  • your test is making a false assumption on the result based on the expected input

This is bad since you want reliable tests. The test should fail only if the code under test does not behave in an expected manner, not for any other reason.

In many cases this comes rather naturally in your code, since you may introduce various abstractions anyway, typically around your data access layer and similar. However, there is one obvious dependency that many systems have, but not many create an abstraction for: time.

Consider that you have a piece of code that validates whether a certain action is valid to perform, and that the rule is that it is OK to perform this action between noon and 6 PM. How do you create a test that tests this in a reliable manner, no matter at what time of day it is executed?

Let’s take it step by step:

[Test]
public void IsValid_Returns_True_At_5PM()
{
    ActionValidator dep = new ActionValidator();
    Assert.IsTrue(dep.IsValid());
}

public class ActionValidator
{
    public bool IsValid()
    {
        DateTime now = DateTime.Now;

        return now.Hour >= 12 && now.Hour < 18;
    }
}

As it happens, I wrote this at 5PM so the test passes as it should, but about one hour later it would fail. This is of course not a reliable test. It’s reliable in the same way as a broken watch; it will still show the correct time twice a day.

What we want here is an abstraction of time, so that we can represent any time of day, at any time of day. One way to do this is to change the IsValid method signature to accept a DateTime value as input and validate against that. However, this can create a class interface that is cluttered with parameters into methods, and that may be quite cumbersome to consume. A better approach would be to create an abstraction that can be injected into the types that need time related data:

public interface IDateTime
{
    DateTime Now { get; }
}

class SystemDateTime : IDateTime
{
    public DateTime Now
    {
        get { return DateTime.Now; }
    }
}

public class ActionValidator
{
    private readonly IDateTime dateTime;

    public ActionValidator() : this(new SystemDateTime()) { }
    public ActionValidator(IDateTime dateTime)
    {
        this.dateTime = dateTime;
    }
    public bool IsValid()
    {
        DateTime now = dateTime.Now;

        return now.Hour >= 12 && now.Hour < 18;
    }
}

Now we can inject an IDateTime provider into the ActionValidator, and have it perform its work. If no IDateTime is expiciltly injected, the ActionValidator will default to using SystemDateTime. But in order to drive our tests, let’s create a fake one:

class DateTimeStub : IDateTime
{
    public DateTime NowValue { get; set; }
    public DateTime Now
    {
        get { return NowValue; }
    }
}

The fake provider has an extra property, NowValue. This enables us to set a hard-coded DateTime value that will be returned by the Now property. This way we can represent any time of day (and date) at time, and write tests that repeatedly will test how our code behaves at that exact instant:

[Test]
public void IsValid_Returns_True_At_5PM()
{
    var dateTime = new DateTimeStub()
    {
        NowValue = new DateTime(2011, 3, 30, 17, 00, 00)
    };
    var actionValidator = new ActionValidator(dateTime);
    Assert.IsTrue(actionValidator.IsValid());
}

Of course, we want to make sure that it does not always return true, but that the validation fails for invalid times as well:

[Test]
public void IsValid_Returns_False_At_7PM()
{
    var dateTime = new DateTimeStub()
    {
        NowValue = new DateTime(2011, 3, 30, 19, 00, 00)

    };
    var actionValidator = new ActionValidator(dateTime);
    Assert.IsFalse(actionValidator.IsValid());
}

Now, while this is a very simple example, it points at something that I think is quite important to think about when writing tests, and designing your code: be aware of what it is that you are actually testing. Only the code that you intend to test should be able to make the test fail. Antyhing else is an unwanted side effect.