HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Time Machine service

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
machineservicetime

Problem

Recently I had someone describe a "Time Machine" service to me; that is, a service that could be used to change how a chunk of code perceives time.

Normally through calls to DateTime.Now and other DateTime statics, time is directly tied to the system clock. A Time Machine service is used instead of the static DateTime calls, and allows external code to change the time it reports. This is especially useful when writing unit tests for services that behave different as time passed due to timers, triggers, etc.

I liked the idea, and decided to implement my own version. Here are the relevant interfaces:

// A service that can travel through time
public interface ITimeTraveler
{
    ITimeMachine TimeMachine { get; set; }
}

// Interface for a Time Machine
public interface ITimeMachine
{
    DateTime Now();
    DateTime UtcNow();
    DateTime Today();
    DateTime UtcToday();
    void TimeTravel(TimeSpan adjustment);
    void TimeTravelTo(DateTime newDateTime);
    void FreezeTime();
    void UnfreezeTime();
    void RevertAllTimeTravel();
    bool IsCurrentlyTimeTraveling();
}


Here is the Time Machine Gist with the full implementation.

This includes two revisions. The first revision was the code I linked to originally, and additional revisions take the feedback here into consideration.

I'm looking for any feedback or suggestions on both the concept of this service and my current implementation.

Solution

I like it.

For some very specific cases where a class needs to be tested and its functionality depends on what System.DateTime.Now returns, then you need an abstraction to wrap the static method calls, if you want to be able to write unit tests that have full control over that dependency.

Your ITimeMachine does that nicely. While a meaningful name, IDateTimeService seems more appropriately generic though. ITimeTraveler might be superfluous.

The dependent code would look like this:

public class MyClass
{
    private readonly IDateTimeService _service;

    public MyClass(IDateTimeService service)
    {
        _service = service;
    }

    public void DoSomething()
    {
        var now = _service.Now(); // instead of DateTime.Now;
        //...
    }
}


I also like that you made Now() a method. It abstracts away the fact that DateTime.Now is really a method in a property suit.

Code Snippets

public class MyClass
{
    private readonly IDateTimeService _service;

    public MyClass(IDateTimeService service)
    {
        _service = service;
    }

    public void DoSomething()
    {
        var now = _service.Now(); // instead of DateTime.Now;
        //...
    }
}

Context

StackExchange Code Review Q#48100, answer score: 4

Revisions (0)

No revisions yet.