Simplcity vs Ease of Injection...
Found myself writing a simple class for implanting "trial" logic for a client (as in you have 30 days left of your trial etc.) ... it relies on the current date and time, and so you can never really be assured your tests are robust unless you can control the current date & time within the test fixture (in fact any time you find yourself writing DateTime.Now alarm bells should be going off... even worse is logic based on DateTime.Now where it's evaluated more the once for a single function).
In the past I've generally Implemented something like an "IClock" interface, which would have a method like "DateTime GetCurrentTime()" or whatever seemed appropriate to the situation... but I decided to go with the lightweight solution of delegates instead in the morning, if only because I was being lazy I didn't see the need for creating an entire interface for such a trivial requirement... so we have:
private DateTime _trialExpirey;
private int _maxExecutions;
private TimeSpan _trialDuration;
private Func_nowFunction; public TrialUpdater(DateTime trialExpirey, int maxExecutions, TimeSpan trialDuration)
: this(delegate { return DateTime.Now; }, trialExpirey, maxExecutions, trialDuration)
{
}public TrialUpdater(Func
nowFunction, DateTime trialExpirey, int maxExecutions, TimeSpan trialDuration)
{
if (nowFunction == null) throw new ArgumentNullException("nowFunction");_nowFunction = nowFunction;
_trialExpirey = trialExpirey;
_maxExecutions = maxExecutions;
_trialDuration = trialDuration;
}
But I'm starting to wonder if this code doesn't smell a bit if I start using it other places... for instance:
- Could I supply an alternative delegate via the castle container...?
- Could I mock out the nowFunction parameter easily using something like RhinoMocks and still have it participate in constraints...?
I'm thinking in the case of mocking it out you would probably need to implement some interfaces which lines up with the generic delegates (Func
Though maybe I've missed something and mocking out delegates is doable with the current RhinoMocks..?
As for being able to inject a value for the nowFunction parameter, I'm thinking a nice solution would be to actually wire it up to a method on another service declaratively i.e.
Which I believe should be doable using a facility and a type converter... but I'm sure the devil's in the detail :)
At any rate, just a minor distraction, back to work.
As an aside the clocks a pretty boring example, but there are times
when you want to manipulate the time for instance:
- If you want to manipulate the time (return dates as UTC instead of Local)
- Clamp the current Time so it's limited to a certain level of accuracy... perhaps you have an external expectation that all dates will be recorded at a 10ms level of accuracy (perhaps you want to align database timestamps with timestamps within your application).
- Perhaps your application uses the clock to work with snapshots of your domain model in the past.
How many people are actually using anonymous delegates and generic Func