Yes, I do.
Since I first saw that fluent and verbose semi-fluent API (Assert.That(actual, Is.Blah(...)))I knew we were to become more than good friends. I saw potential in that relationship.
I know people that just don't like fluent interfaces because they are so in love with their superior dynamic languages and because fluent interfaces came from Java, and we all know that nothing good can come from the enemies, right? (NHibernate, NUnit, Log4Net,... evil or useless code, or worse yet! evil and useless code) </sarcasm>
Jokes aside, it is not just that I believe assertions using this model read slightly better or that arguments are better ordered (in my opinion), but it also allows for better extensibility with less work.
Today's case is (again) against code duplication and as a very nice side effect making our unit tests cleaner and slightly more readable. Not so bad in one go...
Also, as with many of my posts, the code I am going to use is "real" production code. Which I also think is itself a good thing and thus I keep doing it.
Let's put things in perspective: we have a class PresentableType that needs to be presented on a screen. This presentable object has a couple of complex properties (of type ComplexType). It makes a lot of sense that this class can be null or that its properties can be null when we are using the object in our domain, but it does make no sense to have null when we display it on the screen. With these premises what I did was create an extension method that can transform null instances of both the PresentableType and ComplexType into some sort of NullObject (as in NullObject pattern). This null object is a singleton instance of ComplexType (almost same technique used in the framework in multiple places, int.MinValue for instance), so that only one instance of the null object can live and reference checking can be used.
One might argue that an extension method is not the best solution as one may feel weird to invoke a method in a null instance and get a not null result. Particularly I feel this issue bothers me not, and since extension method are a compact and convenient way to add behavior when and where is needed to an already existing object, I am for using it in this case.
Let's have a look at both classes:
And the extension methods:
The problem I was trying to solve was a simple one: how to unit test the extension methods.
One simple way of doing it is using standard assertions over each an every of the properties of PresentableType. It works, no doubt about it, but it's ugly and generates a lot of duplication for all the possible cases: instance on PresentableType is null, the instance is not null but both complex properties are, only one of the properties is null, etc... Code is worth a thousand words:
Why not hide all that duplication under a NUnit Constraint type that is applied to the PresentableType instance (or null, for what is worth)? Actually we would need a couple of cases to handle, as the case in which the instance is null is slightly different, requiring different assertions. No problem, as a different class is created for that purpose. Let's have a look at how these constraints look like:
And let's see how a unit test might look with this extended Constraint:
Concise. Right? But if at the beginning of this long post I mentioned that I liked how the assertion can be read, I just stepped back on that front. But with a little effort we can make it look nicer. Making things look nicer in unit tests is not always (mostly never) a requirement, but if it helps readability I consider it's for the good. What if we could use a static builder, the very same way NUnit uses the SyntaxHelpers.Is class? A bit of a trick with static properties and extension methods...
...leaves the syntax of the tests concise, pretty readable and free of duplication. For those who say that is has to be pretty self-explaining what the unit test does, the real "meat" of the assertion is just one click away. Note that the lines "Assert.That(subject, Must.Be.PartiallyConstrained(instance));" and "Assert.That(subject, Must.Be.PartiallyConstrained().By(instance));" are completely equivalent. They are just a bit of an experiment that I was doing while migrating the code to be "bloggable":
Not that bad for testing code, uh?