xUnit.net Goes 1.0 and Unit Testing F#
xUnit.net 1.0 Goes Live
As Brad Wilson said earlier this week, xUnit.net released version 1.0. You can read more about the announcement here. Since the RC3 timeframe, it was pretty much feature complete, so there hasn't been much change since that time. Instead, the focus was on polishing the existing functionality and including the integration with ASP.NET MVC, Resharper 3.1 and TestDriven.NET. The GUI runner, such as it is has been pretty limited, but ok for most purposes.
Many questions used to arise, why xUnit.net? Why do we need yet another framework out there? Why not just add onto the existing ones in the market? I think with the 1.0 release, the critics in this release to do things a bit differently than MbUnit and NUnit have approached things. For example, the Assert.Throws<TException>, not having to decorate the classes with [TestFixture] and a few other things come to mind as well as being very extensible. It's a smaller framework, but I really don't have a problem with that. With most of the other frameworks, I don't use half of it anyways.
So, why do I care as much as I do about this one over say others at the moment? Well, it's great that we have such choices in the market now. As Scott Hanselman said at ALT.NET Open Spaces, Seattle, he's a StructureMap, Moq and xUnit.net guy. I'll get into the reason shortly enough.
The Traditional Way
When you think of doing your unit or behavior tests, you often need a class and decorate with attributes, have a initialize and teardown and all that goodness. Since F# is considered a multi-purpose language, this works just fine. That's the beauty of F# and hopefully will drive its adoption into the marketplace. So, consider the following functions with the appropriate tests in a more traditional way such as NUnit within Gallio. I am trying out Gallio so that I can see how well it reacts to F# as well as just kicking the tires. I highly recommend you at least check it out.
Anyhow, back to the code. Let's take a simple example of a naive routing table through pattern matching, to see whether a call is allowed or not. Like I said, naive, but proves a point with pattern matching.
#light
#R @"D:\Program Files\Gallio\bin\NUnit\nunit.core.dll"
#R @"D:\Program Files\Gallio\bin\NUnit\nunit.framework.dll"
let FilterCall protocol port =
match(protocol, port) with
| "tcp", _ when port = 21 || port = 23 || port = 25 -> true
| "http", _ when port = 80 || port = 8080 -> true
| "https", 443 -> true
| _ -> false
open NUnit.Framework
[<TestFixture>]
type PatternMatchingFixture = class
[<Test>]
member x.FilterCall_HttpWithPort8888_ShouldReturnFalse() =
Assert.IsFalse(FilterCall "http" 8888)
[<Test>]
member x.FilterCall_TcpWithPort23_ShouldReturnTruee() =
Assert.IsTrue(FilterCall "tcp" 23)
end
Unfortunately of course for me, the Gallio Icarus Runner doesn't really work well for me at the moment with F# integration. Instead, I get all sorts of issues when doing so. This is where I get the large FAIL.
This seems to repeat itself unfortunately for the xUnit.net and MbUnit integration as well, so it's not quite ready for primetime in the F# space. Also, when I exit the application, there is a Gallio session runner that keeps running in memory and therefore I can't perform any builds. So, I have to manually go into Task Manager and kill the process. Not the best experience I've ever had... So, for now, the limited functionality in the xUnit.net GUI Runner works for me.
The More Functional Way
Instead, we see a lot of pomp and circumstance that we just don't need. In the functional world, a lot of the time, we don't want or need to create these classes just to test our functions. After all, most of what we do has no side effects or at least should be (and are code smells mostly if they are not, but that's another post for another time).
At the request of Harry Pierson, another F# aficionado and IronPython PM, talked to Brad and Jim Newkirk about adding static function unit test capabilities to xUnit.net. And sure enough, we now have them, so let's compress the above code into something that looks more like F#.
#light
#R @"D:\Tools\xunit-1.0\xunit.dll"
open Xunit
let FilterCall protocol port =
match(protocol, port) with
| "tcp", _ when port = 21 || port = 23 || port = 25 -> true
| "http", _ when port = 80 || port = 8080 -> true
| "https", 443 -> true
| _ -> false
[<Fact>]
let FilterCall_TcpWithPort23_ShouldReturnTrue () =
Assert.True(FilterCall "tcp" 23)
[<Fact>]
let FilterCall_HttpWithPort8888_ShouldReturnFalse () =
Assert.False(FilterCall "http" 8888)
So, as you can see, I compressed the code quite a bit from here. Since I'm doing functions and nothing more with just some basic pattern matching, this approach works perfectly. That's why I am a fan of this. Open up the GUI runner or just the ever popular console runner, and run it through and sure enough, we get some positive results.
The interesting thing to see upcoming is how well the TDD space will play in the functional programming space. I don't think it should be any different of an experience, but time will tell.
Where to Go?
From here, where do we go? Well, I'm sure the GUI Runner of xUnit.net will get better over time, but the Gallio folks are pushing for the Icarus Runner. Right now, only the xUnit.net runner works for me, so that's what I'm going to stick with at the moment.
An interesting thought occurred to me though. Are the unit tests we're doing mostly nowadays purely functional anyways? Would it make sense to test some C# code in F# to produce cleaner code? Not sure, but I like the idea of having that choice. Or even for that matter, writing my unit tests in Ruby for my staticly typed C# code. Within the .NET framework space, the possibilities are vast. And that's the really cool thing about it. But will we see an IronPython or IronRuby testing framework within the .NET space?