views:

139

answers:

2

Hi

I am wondering how to you test TimeZone logic? For me my timezone stuff is used to filter data from the database(what of course in unit tests gets mocked up and not tested).

But I would like to test the logic around it to see if I give certain times in that it would be converted right.

I am not sure how to do this though.

+1  A: 

It's not entirely clear what you mean.

Do you use the current time zone of the system? If so, I suggest you include some sort of intermediary static property which can be reset just for tests to let you "pretend" that you're in a different time zone just for the duration of a test. Admittedly it means you have to be scrupulous about always using that property.

I dare say there's a Win32 system call you could use to change the system time zone, but that sounds a bit drastic - it's a shame there's no idea of the current time zone of a thread like there is for cultures :( (There's TimeZoneInfo.Local, but there's no managed way of changing that, as far as I've seen.)

If you're not using the local time zone, just make sure that your API takes all the information you need to write tests, so you can make sure that if you process dates and times in particular time zones, you get the right answer. If it would be useful to you, I can think up some good corner cases to test against. In particular, there are time zones where there's no local midnight once a year (when daylight savings stops) which can screw up some cases.

Jon Skeet
Jon, would this be a good candidate for a data-driven unit test?
Robert Harvey
It's almost certainly data driven, yes. Whether you use explicit support for that in your unit test framework is up to you (and the framework) of course. But my calendar sync code definitely has a bunch of tests with interesting dates and time zones...
Jon Skeet
How my system works is that the user can change on the site the time zone they are from. So my stuff is all stored in UTC in the db and I convert back and forth depending on their timezone(if non is given UTC is used to figure out stuff for that user until changed). So I just would like to make sure the right logic is happening at the right time for the user. So if they set something for a certain day that it gets converted proper and all results that they should see are seen.
chobo2
Okay, so that sounds like you need test data in UTC, along with test time zones and expected results. A relatively simple data-driven test.
Jon Skeet
Shouldn't that be "intermediary NON-static property"?
Wim Coenen
@wcoenen: To avoid having to inject a "local timezone provider" everywhere, I'd *probably* use a static member. That's less pure, admittedly... but a lot simpler.
Jon Skeet
+1  A: 
public class ClassToTest
{
    public Func<TimeZone> TimeZoneProvider = () => TimeZone.CurrentTimeZone;

    public void MethodToTest()
    {
        var timeZone = TimeZoneProvider();
        // Do something with the time zone
    }
}

[TestMethod]
public void Test()
{
    // Arrange
    var sut = new ClassToTest();
    sut.TimeZoneProvider = () => ... // return the time zone you would like for the test

    // Act
    sut.MethodToTest();

    // Assert
    // ...
}


EDIT: Another alternative would be to use constructor injection to pass a time zone into your class:

public class ClassToTest
{
    private readonly TimeZone _timeZone;
    public ClassToTest(TimeZone timeZone)
    {
        _timeZone = timeZone;
    }

    public void MethodToTest()
    {
        // Do something with _timeZone
    }
}

[TestMethod]
public void Test()
{
    // Arrange
    var timeZone = ... // return the time zone you would like for the test
    var sut = new ClassToTest(timeZone);

    // Act
    sut.MethodToTest();

    // Assert
    // ...
}
Darin Dimitrov
What your first line do? The one with = () => ?
chobo2
The field TimeZonProvider represents a function which returns the current time zone and takes no argument. It is defined as an anonymous function using lambda expression. This function could be replaced in the test by another function which returns a different time zone. Another method would be to just use constructor injection for the time zone. I've modified my post to show it.
Darin Dimitrov