Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

xUnit.net Goes 1.0 and Unit Testing F#

As I’ve said before on my previous blogs, I’m very much into F# and functional programming lately.  With that, I’m still in the mode of TDD.  Just because you enter a new programming paradigm, doesn’t mean you throw away your XP and TDD roots.  Instead, I find it just as valuable if not even more so when switching to a new model.

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?

This entry was posted in F#, Functional Programming, TDD/BDD. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://podwysocki.codebetter.com Matthew.Podwysocki

    @Jamie

    You’re probably right and it was some mistake on both of our parts. But what I do like is the option of leaving off the TestFixture and having the ability to still run tests. I don’t see any real reason for test fixtures, and instead running tests through modules works nicely for me.

    Matt

  • http://weblogs.asp.net/nunitaddin Jamie Cansdale

    I think your original example might have worked if you’d added a “( )” after “PatternMatchingFixture”. Without it the class doesn’t get a public parameterless constructor.

    E.g. try it like this instead:
    []
    type PatternMatchingFixture( ) = class …

    BTW, I’m currently working on F# support in TestDriven.Net. I found your unit testing examples in F# useful. :-)

    Regards,
    Jamie.

  • http://podwysocki.codebetter.com Matthew Podwysocki

    @Charles

    You are correct that it is broken. The change is that F#, with the new build has now created static classes instead of normal classes for hosting the test methods which will indeed break xUnit.net. xUnit.net is expecting classes that are not abstract (which static classes are), therefore it won’t scan to find the method and execute it. I’m not sure of the workaround, other than creating test classes for now, until the problem has been resolved.

    Matt

  • Charles Miles

    I love the testing style you showed in this post – not having to wrap a class type around the test – great!

    But when I tried this out with xUnit 1.0 and F# 1.9.4.15 I ran into problems with the test runner not seeing the tests – I posted about my problems this up on the xUnit Codeplex site – http://www.codeplex.com/xunit/Thread/View.aspx?ThreadId=27866
    Brad Wilson responded that “The problem appears to be that the F# class that is created is marked as abstract in the CLR” – is this a problem that you have run into? am I missing a compilation or code syntax option?