Should Extensions
UPDATE (6/9/09): Get the code here.
Some months ago I started wrapping my test asserts in fluent “should” extensions, like this:
public static T ShouldEqual<T>(this T actual, T expected) { Assert.AreEqual(expected, actual); return actual; }
Some of these extensions do a little more than just wrap assertions, for example:
public static T ShouldContainOne<T>(this IEnumerable<T> e, Func<T, bool> predicate) { var match = e.ShouldContainAtLeastOne(predicate); if (match.Count() != 1) { Assert.Fail("Expecting 1 matching item. Found {0}.", match.Count()); } return match.First(); }
Reuse Dilemma
I put these extension methods in a static class in a helper project for re-use across test projects within the application. Then one day I began work on a new application for a new client. I love my “should” extensions and felt I could not live without them. Cut-and-paste to the rescue. Yuck. Now I am on to another application. Cut-and-paste again. Get me off this merry-go-round!
I considered creating a common assembly to share across my projects. However, as a consultant I prefer not to leave behind binary bits with this client and that client.
Making matters worse, the aforementioned applications do not all use the same testing framework.
Solution
So I have started developing a library of reusable “should” extensions that I am planning to release as open source – tentatively named “ShouldIt.” It will plug-and-play with all the major unit testing frameworks – with zero configuration using MEF. To use it, with NUnit for example, you will reference ShouldIt.Core, ShouldIt.Clr and ShouldIt.NUnit in your test project.
You might be wondering, what is ShouldIt.Clr, and why is it separate from ShouldIt.Core? ShouldIt.Clr will provide extensions to the CLR base class library types. This leaves room to add, for example, ShouldIt.Watin.
By the way I considered writing my own assertions instead of wrapping those provided by the testing framework. Then I opened NUnit and MbUnit in Reflector. Whew! There’s a lot more to those simple-looking assertions than I had expected.
Challenges And Questions
The biggest challenge I foresee is managing multiple binary dependencies to the testing frameworks. This is mitigated by the fact that references will not be version specific. Hence, pain will only be felt when the Assert APIs, more specifically those methods that ShouldIt calls, are changed. I expect that those APIs are fairly stable. That said, we can expect major releases to have breaking changes, as we have seen recently with MbUnit 3 (Gallio).
My questions for you:
- Anyone else feeling this pain?
- Has someone solved this already and I just have not seen it?
- Can you think of a better name than “ShouldIt?”