Fun With NUnit 2.4 and Extension Methods
It's been a while since I played with NUnit. This is mainly due to the chip that *they* implanted in my head that gives me a migraine when I stray from VSTS unit tests.
NOTE: at this point, you may be wondering - if that's the case, how were you able to write this blog entry. Red wine, dear friends, red wine...
So like I was saying, I was playing with NUnit 2.4.3 tonight and wanted to point out a few things that were new to me - and then show you how I took one new feature just a bit further by using new language features in Visual Studio 2008.
First, a few things that I thought were cool in NUnit 2.4. Note that some of these things have been around earlier than 2.4.x - but I didn't know about them - therefore, they're new <g>.
- ExpectedExceptionAttribute now allows for pattern matching (even regular expressions) on the error message – Here's the downside. While supported in the NUnit GUI and console runners, it’s NOT supported in the R# VS Runner – ARRGGGHHHH!!! Please go to the JetBrians JIRA site and vote that this gets fixed ASAP!!
- Explicit attribute – causes a test or test fixture to be ignored unless specifically selected for running – this seems kind of handy in some cases, but with R# test sessions, I can’t imagine needing it all that much.
- PlatformAttribute – man, how did I miss this one? Allows you to specify tests that will only be run if the platform condition is satisfied (exclude property allows the converse)
- PropertyAttribute – new to 2.4 – curious about playing around with this. If anyone has some specific use cases where this has come in handy, please share!
- SetCultureAttribute – great way to handle test cases where business logic varies by region.
- SetUpFixtureAttribute – specified on a class and essentially allows for the class to provide global TestFixtureSetup and TestFixtureTeardown functionality to all TestFixtures within a given namespace. I’m really interested in getting a better idea on what was the use case for creating this feature. Again, if anyone has specific use cases where this has proven invaluable, do tell.
- New way of doing assertions (constraint-based) seems like a syntax that puts us on the path towards a more natural expression.
And on that note...
I was really enamored with the new syntax for assertions. To give you a more concrete example. Take the following NUnit 2.x test to compare ages.
[Test]
public void IsOlderTestNUnit2x() {
Person howard = new Person("Howard", "Dierking") {
Birthday = new DateTime(1977, 3, 11) };
Person jenn = new Person("Jennifer", "Dierking") {
Birthday = new DateTime(1976, 3, 3) };
Assert.Less(jenn.Birthday, howard.Birthday);
}
Pretty simple. However, the syntax here forces you to slow down a bit and consider the order of parameters - put another way, the syntax flattens the logical flow of the expression. NUnit 2.4 adds a new way of expressing assertions that is a bit closer to natural language - check out the constraint-based approach...
[Test]
public void IsOlderTestNUnitConstraint() {
Person howard = new Person("Howard", "Dierking") {
Birthday = new DateTime(1977, 3, 11) };
Person jenn = new Person("Jennifer", "Dierking") {
Birthday = new DateTime(1976, 3, 3) };
Assert.That(jenn.Birthday, Is.LessThan(howard.Birthday));
}
I thought that this was a pretty cool way of representing things. The one thing that kept bugging me, though was the fact that I still had to use 2 arguments to express what was, to me, one logical idea. So then I thought, "Hey, wouldn't this be a cool use of extension methods?" So I fired up my VS 2008 VPC (NOTE TO SELF: Until I have a 4 proc machine with 8 GB of RAM, I will NEVER AGAIN install Vista on a VPC) and tried it out. The extension methods themselves were incredibly easy.
public static class SyntaxHelperExtensions
{
public static bool IsGreaterThan(this IComparable expected, IComparable actual) {
return expected.CompareTo(actual) > 0;
}
public static bool IsLessThan(this IComparable expected, IComparable actual) {
return expected.CompareTo(actual) < 0;
}
}
And the result? As advertised, 1 baby step closer to a more natural expression of my test.
[Test]
public void IsOlderTestExtensions() {
Person howard = new Person("Howard", "Dierking") {
Birthday = new DateTime(1977, 3, 11) };
Person jenn = new Person("Jennifer", "Dierking") {
Birthday = new DateTime(1976, 3, 3) };
Assert.That(jenn.Birthday.IsLessThan(howard.Birthday));
}
Now to just get some new keywords in the language!
I am currently the Editor-in-Chief for MSDN Magazine. I joined Microsoft in 2006 as a product planner with the certification team at Microsoft Learning. Prior to that, I spent my career as a developer and later as an architect. My main technology passions include pretty much anything on language theory, agile development, and service-oriented architecture.