StormianRootSolver
StormianRootSolver

Reputation: 535

Unit testing a time - based component?

So I'm writing a cache system (not too complicated, but it has very nice semantics) with a ttl (time to live) for items.

Of course the ttl must be unit tested, but since one can't inject a new implementaton of "IDateTime" or "ITimeSpan" in C# (because there is no such thing), how would you go about that?

Write a new component "IDateTimeProvider" and "DateTimeProvider" first, which one can mockup then?

Isn't reimplementing parts of the .NET runtime library... overkill?

Edit: Thank you all for your amazing answers! I know now exactly what I'm going to do!

Upvotes: 6

Views: 2359

Answers (5)

PHeiberg
PHeiberg

Reputation: 29861

I usually use a variation of Ayende's solution.

public static class SystemTime
{
    public static Func<DateTime> DateProvider = () => DateTime.Now;

    public static DateTime Now { get { return DateProvider(); } }
}

In the code under test you can now use SystemTime.Now to get the current time:

var currentTime = SystemTime.Now;

And in the test you can set the current time to a known value:

SystemTime.DateProvider = () => new DateTime(2010,6,25);

Upvotes: 6

nas
nas

Reputation: 977

You might want to see this question:

How do I MOQ the System.IO.FileInfo class... or any other class without an interface?

In a nutshell you'll either need to make a wrapper class yourself, or use a library that already provides wrapper classes for DateTime, like SystemWrapper.

Upvotes: 4

xtofl
xtofl

Reputation: 41519

If you're having trouble inventing some mockup object, I think it'ld be good to rethink the testability of your component.

Maybe the ttl logic should be testable on it's own, somewhat like this:

TTLlogic l = new TTLLogic( 10 );
DateTime startdate = now();
Object item=new String();
l.addItem( startdate, item );

l.setTime( startdate.addSeconds( 5 ) );
assert( l.items().contains( item ) );

l.setTime( startdate.addSeconds( 10 ) );
assert( l.items().empty() );

Upvotes: 2

Dr Herbie
Dr Herbie

Reputation: 3940

An IDateTime provider might prove useful in other ways -- if your cache is to be used between client and server apps running on separate machines, you will one one single time-source for both machines (usually the server) otherwise the times may be out of step. I you use the IDateTimeProvider interface everywhere, then the client can use a version that gets the time from the server.

You would get that plus the Unit-testing de-coupling.

Upvotes: 2

Maxem
Maxem

Reputation: 2684

how would writing an IDateTimeProvider be reimplementing parts of the .Net Framework?

You'd just have two implementations, one that returns DateTime.Now and another that returns a value you specified before.

Upvotes: 4

Related Questions