6

If you build systems where business processes depend on what time it is[1], you cannot use DateTime.Now or similar in your code, as you will have to deal in tests with e.g., future End Of Month or End Of Year scenarios. Changing the operating system time is generally not an option when you use SSL certificates and because it is complex to do correct for a distributed system.

One option is create a singleton service accessible by all systems that returns the current time. In production it could return DateTime.Now and in tests it could return a game time like 28th of February in a End Of Month scenario.

But is there better way of doing this? Like a more database oriented approach because it leads to better performance? Or would you put in a distributed cache? Is there some well-known design pattern for this?

[1] typical example: business processes implemented by insurance system, core banking system, ...

Ibrahim Najjar
  • 19,178
  • 4
  • 69
  • 95
Lars Nielsen
  • 365
  • 1
  • 2
  • 14
  • I like the use of frameworks like Fakes to control of time in normal tests. You can also use e.g., Unity to extract time from production code, meaning you inject a game-time in tests and DateTime.Now. However, you cannot fully rely on this approach when you build larger systems for the finance sector as these types tests are often user driven. A normal example: an administrator (can be business) uploads a new set of business parameters (like interest rate) to a test environment and would like to verify how the system reacts from a business point of view. They must be able to change the time. – Lars Nielsen Oct 15 '13 at 11:32

5 Answers5

4

One way to deal with this issue is to have a clock interface:

public interface IClock {
  DateTime Now { get; }
}

And use this interface throughout your code, in place of DateTime.Now. In production, you'll use its canonical implementation (or a UTC variant):

public class SystemClock implements IClock {
  public DateTime Now { get { return DateTime.Now; } }
}

You can, e.g., use SystemClock as a default in all classes that need IClock and allow other implementations to be injected through constructors or setters.

In tests, you can create a test implementation or mock it with a mocking framework.

Jordão
  • 55,340
  • 13
  • 112
  • 144
2

You could look into using Microsoft Fakes to achieve what you're talking about.

See this slightly modified example;

[TestMethod]
public void TestCurrentYear()
{
    int fixedYear = 2000;

    // Shims can be used only in a ShimsContext:
    using (ShimsContext.Create())
    {
        // Arrange:
        // Shim DateTime.Now to return a fixed date:
        System.Fakes.ShimDateTime.NowGet =  
        () =>
        { return new DateTime(fixedYear, 1, 1); };

        // Act:
        int year = DateTime.Now.Year;

        // Assert: 
        Assert.AreEqual(fixedYear, year);
    }
}

The advantage here is that you don't have to change any code that uses DateTime to make it testable.

Chris McAtackney
  • 5,192
  • 8
  • 45
  • 69
2

Where date and time is critical and complex (especially due to timezones and DST), which I imagine is the case in the industries you mentioned, you might want to avoid DateTime in favour of Noda time.

Noda time has unit testing capabilities built in see https://stackoverflow.com/a/14531915/360211

Community
  • 1
  • 1
weston
  • 54,145
  • 21
  • 145
  • 203
1

For unit testing, you should be able to stub anything out, including the time. Some mocking frameworks (e.g. Microsoft Shims) allow you to override the behaviour of DateTime.Now.

For integration/system testing, what I've done in the past is use a configuration setting for each system component that specifies a DateTime offset for that component to use from the real DateTime. This could be set by an undocumented app.config setting, where if the setting is absent, normal behaviour applies. You'd need to be careful that this doesn't introduce any vulnerabilities however.

Rob
  • 4,327
  • 6
  • 29
  • 55
0

I have concluded the following approach will work:

Unit tests:

  • Mocking framework, to control the time as desired

Integration tests, User driven tests & production:

  • Dependency injection, used to inject a test approach or production approach
  • Test approach: ask a NTP server for what time it is. This NTP server will be connected to all relevant applications rather than servers, which have their own. The NTP server will have as a standard an interface that allows programs like a test portal or administrator tools to change it as needed.
  • Production approach: ask system time, which is the time from the NTP server connected to all servers

Here is C# code for calling a NTP server: calling NTP server from C#

Lars

Community
  • 1
  • 1
Lars Nielsen
  • 365
  • 1
  • 2
  • 14