views:

73

answers:

5

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!

+4  A: 

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.

Maxem
The important part being that you're not reimplementing most of DateTime at all - you're *only* extracting out the "current time" part.
Jon Skeet
+3  A: 

You might want to see this question:

http://stackoverflow.com/questions/1582596/how-do-i-moq-the-system-io-fileinfo-class-or-any-other-class-without-an-interf

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.

Alex M.
In other words, no, it's not overkill. When the client code is not testable, you have to do what you have to do.
apollodude217
+2  A: 

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.

Dr Herbie
+2  A: 

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() );
xtofl
+3  A: 

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);
PHeiberg