As you may notice on my blog lately, I've been focusing on design and functional programming lately. There is a lot to explore in terms of those two topics in the next series of blog posts especially around xUnit frameworks, QuickCheck and other ideas. But, first I want to turn my attention a combination that is working great for me as I develop solutions using F# which includes TestDriven.NET and xUnit.net.
Very recently, I was talking with a few people about testing options in F#, when TestDriven.NET was mentioned once again. A month or so ago, Jamie Cansdale had a series of blog posts on using F# with TestDriven.NET which intrigued me quite a bit here. I then decided to give it a spin, only to have issues with the differences between the x86 version and x64 version in terms of proper registration, and there were some workarounds I had to do in order to get it to work.
Flash forward to a couple of days ago when Jamie announced the release of TD.NET 2.18 which fixed those issues so now F# tests should work with any given test framework that has an integration with it. Along with this announcement was the announcement of NUnit 2.5 beta which no longer requires a TestFixture attribute for your fixtures, and allows for the addition of the Test attribute to any static method, which is a feature that is had by xUnit.net and MbUnit as well.
I am particularly fond of using xUnit.net as my unit testing framework of choice. This was the first framework to support static test methods, so that in my F# code, I don't need to create a given class for my tests, and instead bundle them inside a module. Also, the framework is lightweight and perfectly opinionated for what I need.
In order to enable xUnit.net support for TestDriven.NET, simply launch the xunit.installer.exe which will then allow you to enable integration. That should look similar to below.
Now when we put them together, that's when the fun begins.
Putting Them Together
Let's define a simple intersperse function that inserts a given item between each element in the list. It's a function that I think should be on the ListModule itself, as well as DropWhile, Delete and a few others. Not to mention treating a string as a list of char instead of a seq<char> but that's for another post.
let intersperse_with_list_should_insert() =
let l = ['a'..'z']
let i = '|'
let r = ListExtensions.intersperse i l
Assert.Equal(51, List.length r)
r |> List.filter(fun x -> x = '|') |> List.length)
And then the code required to implement this functionality might look like something below. This implementation is very similar to the Haskell version.
module ListExtensions =
let rec intersperse (i:'a) (l:'a list) : 'a list =
match (i, l) with
| _,  -> 
| _, [x] -> [x]
| sep, x::xs -> x :: sep :: intersperse sep xs
Once completed, I can now compile and run my test and the results are shown below:
It's great now to have a complete solution sitting inside Visual Studio. But of course that leaves out one important aspect of TDD. Refactoring...
What is the story around F# and refactoring tools? It's too early to say, I think. Probably the easiest refactoring opportunity would be rename or move, but after that, things get more complicated. Not only do you need to worry about the same things that C# does in terms of imperative and object oriented principles, but also adding functional principles as well make for an interesting product.
But, what about the functional programming populace at large? Well, Haskell does have an answer in the form of HaRe, The Haskell Refactorer. This demo using GVim gives a good idea of some of the capabilities of such refactoring software such as add parameter, remove parameter, introduce new function, and many others. Erlang as well has an answer from the same group who brought you HaRe in the form of Wrangler. Both tools show some interesting promise around refactoring tools for functional languages. There is a bit of research and this shows great promise of things to come I hope.
Wrapping It Up
It's great to see the community coming around to support F# in a way to help us be more productive. With the integration of TestDriven.NET and xUnit.net has definitely been a blessing for those interesting in a more complete solution. With a bit of research going into refactoring tools for functional languages, it's only a matter of time before we start seeing the first on the market dedicated to F#.
Next time, I hope to get to covering more basic issues around functional programming and TDD which leads me to such things as xUnit frameworks and QuickCheck and when to use what. This discussion I hope to have as part of our Real World Haskell book club as chapter 11 is dedicated to testing in Haskell. We'd love to have you as part of the conversation.