Welcome to MSDN Blogs Sign in | Join | Help

Testing Against The Current Time

This is the third in a small series of posts about testing against non-determinism. In this installation, I'm going to cover how to deal with the current time or date.

If you have logic that is dependent of the current time or date, test results will vary according to the time you run your tests. As always, my examples tend toward the overly simplistic, but consider this method:

public bool IsTodayAWeekDay()
{
    DateTime now = DateTime.Now;
 
    if ((now.DayOfWeek == DayOfWeek.Saturday) ||
        (now.DayOfWeek == DayOfWeek.Sunday))
    {
        return false;
    }
 
    return true;
}

The main point of this example is that the code braches on the value of DateTime.Now. Obviously, if you execute a test against this method on a weekday, the method will return true, but otherwise it will return false.

[TestMethod]
public void UseNonDeterministicTimeConsumer()
{
    NonDeterministicTimeConsumer tc = new NonDeterministicTimeConsumer();
 
    bool result = tc.IsTodayAWeekDay();
 
    // How to verify result?
}

As you can see, you can't really test this method. A quick fix for this could be to change the method's signature to accept the current time as a parameter, but this may not be a good idea for a number of reasons (which I'll leave as an exercise for the interested reader).

If changing the method's signature is not an option, then how can you test such a method?

This is a case where the Provider Injection pattern really comes into its own. Unlike other Inversion of Control patterns, Provider Injection can delay the creation of a dependency until it is needed. Since the current time is continually changing, you should never request an instance before you need it, and that's exactly what you can do with Provider Injection.

As always, I'm using Service Locator 2's ServiceProvider<T>, but you can always use an implementation of IServiceProvider and do a bit of casting if you want to stick to the BCL proper.

public partial class TimeConsumer
{
    private ServiceProvider<DateTime> dateTimeProvider_;
 
    public TimeConsumer(ServiceProvider<DateTime> dateTimeProvider)
    {
        this.dateTimeProvider_ = dateTimeProvider;
    }
 
    public bool IsTodayAWeekDay()
    {
        DateTime now = this.dateTimeProvider_.Create("Now");
 
        if ((now.DayOfWeek == DayOfWeek.Saturday) ||
            (now.DayOfWeek == DayOfWeek.Sunday))
        {
            return false;
        }
 
        return true;
    }
}

The trick is to defer creation of the DateTime instance until you need it. Incidentally, you see here a rather nice feature of Service Locator 2 illustrated: Requesting a DateTime instance named "Now" allows Service Locator to distinguish between several requested DateTime objects (you might also want to be able to create what corresponds to DateTime.Today), but it also allows Service Locator to infer the correct creation strategy for the requested instance. This means that unless you intercept it by presetting or configuring a value, ServiceProvider<DateTime> will simply use DateTime.Now.

In the test, however, you do want to intercept the default strategy by presetting the current time to a predefined value:

[TestMethod]
public void CheckMonday()
{
    ServiceProvider<DateTime> dateTimeProvider = 
        new ServiceProvider<DateTime>();
    // 2007-05-07 is a Monday
    dateTimeProvider.Preset(new DateTime(2007, 5, 7), "Now");
 
    TimeConsumer tc = new TimeConsumer(dateTimeProvider);
 
    Assert.IsTrue(tc.IsTodayAWeekDay());
}

When executed, the Create method will always return the preset instance - in this case alway May 7th, 2007, which is a Monday. Obviously, you can write similar tests for the other days of the week.

Next: Testing Against The Passage of Time

Published Saturday, May 12, 2007 8:45 PM by ploeh

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# ploeh blog : Testing Against Non-Determinism

Saturday, May 12, 2007 2:47 PM by ploeh blog : Testing Against Non-Determinism

# Testing Against Guids

Saturday, May 12, 2007 2:47 PM by ploeh blog

This is the second in a small series of posts about testing against non-determinism. In this installation,

# re: Testing Against The Current Time

Sunday, May 13, 2007 1:19 PM by kost

If you do not take the time zone into consideration, CheckMonday() may not return the same result if run on two different computers.

While UTC is good for log files, I would recommend a time zone that takes account of daylight saving times; otherwise you will have to change any reconfiguration twice a year.

Kost

# re: Testing Against The Current Time

Monday, May 14, 2007 4:06 AM by ploeh

Hi Kost :)

Thank you for your comment. I'm not sure I understand why the CheckMonday test may yield a different result on different machines.

No matter the time zone of the machine, the injected date is May 7th, 2007. Since the test is calling the test target via an in-process call, the time zone of the test code is always the same as the time zone of the test target.

Thus, I think May 7th, 2007 will always be May 7th, 2007, or am I missing your point?

# Testing Against The Passage of Time

Monday, May 14, 2007 1:08 PM by ploeh blog

This is the fourth in a small series of posts about testing against non-determinism. In this installation,

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker