We were writing some tests that need a couple instances of a data object. Well, my first test new-ed up the instance and added it to the collection. This instance needed to have the due date property set, so I did something like this:
Well, there's a bit of annoying duplication there, so I changed it to:
with a method later on that looks like this
Okay, a bit better.
A little bit later, we had another test fixture that used the data object in a similar way, so I was looking for a way to bring the thing() method into a scope that was available for the other fixture, as well. When I was doing 2.0, I would have probably built a base class for my test fixtures and subclasses it in both fixtures. Yuk! Those who know me know that I have a special, black, cold place in my heart for subclassing like this.
Enter extension methods
I want a way to have some utility methods that I can use whenever I have a fixture that needs to build things. Aha! Let's make an interface:
public interface TestsThings {}
And, add an extension method to it:
Cool. Now, my test fixtures can implement TestsThings and get the method, so the construction of the lists will now look like this:
Unnecessary Construction Parameters? Yuk!
Well, not happy to leave a bad thing bad, I decided to take it one step further. I want to be able to write
How to do that? Hmm.... Ah, here we go. Let's change ThingTestingUtilities to look like this:
Works much better. But, there is still a matter of duplication in the DateTime.Now... stuff. So, let's take this a step further. What if I could write this:
That looks much better. Yeah, if I was in a different language, I'd do something like:
this.NewThings().WithAnOffsetDueDate(1.days);
[Update: Steven Harman alerted me that you can do this. I'm too lazy right now to implement it, though. Maybe later]
[Update2: Leon Gersin added a comment showing how to extend it like 1.days. Check it out.]
So, let's add a helper method. The utility class looks like this now:
Cool, compiles, runs, now my construction looks like this:
Extension methods can definitely help do some neat stuff. I don't have to subclass, I can add methods by simply implementing an interface. This also gives me the ability to create interfaces that are focused on different tasks that my test fixtures might need, so I don't have to load up subclasses with unnecessary mixes of unrelated methods.