CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Matthew Podwysocki

Life of a Functional Programmer

The Unit Testing Story in F# Revisited

Last week I posted about some troubles I was having with the unit testing frameworks for F#.  Today, Brad Wilson announced the release of xUnit.net 1.0.1 which addressed the change in the F# compiler as well as integration with ASP.NET MVC Preview 3 which was just released.  As always you can find the latest bits on CodePlex.  There was a change in the way F# was compiling the modules as static classes which was not expected in previous versions. 

Running the Tests Again

Now, I'm able to run my functions just as before and the runner will now recognize them.  Below is just a simple example of some unit tests to determine whether numbers are prime or not.  I'm extending the System.Int32 to add a property to the instance to determine whether it is prime.  Just to prove a point on how flexible F# really is, I'm also able to extend the Int32 class using static methods, something that you cannot do with C# and extension methods.  More and more, I love the language itself and finding myself trapped sometimes by the limits of C#.  But, that's sidetracking, so let's get to the unit tests.

#light

#R @"D:\Tools\xunit-1.0.1\xunit.dll"

open Xunit

let isPrimeNumber(i) =
  let limit = int(sqrt(float(i)))
  let rec check j =
    j > limit or (i % j <> 0 && check(j + 1))
  check 2
   
type System.Int32 with
  member i.IsPrime
    with get () = isPrimeNumber(i)
   
  static member IsPrimeNumber(x) =
    isPrimeNumber(x)

[<Fact>]
let IsPrime_WithPrimeNumber_ShouldReturnTrue() =
  Assert.True((7).IsPrime)
   
[<Fact>]
let IsPrime_WithNonPrimeNumber_ShouldReturnFalse() =
  Assert.False((21).IsPrime)
  Assert.False(System.Int32.IsPrimeNumber(45))

And then when I run it through the GUI runner, I sure enough get two passing tests.  It was asked of me last week at the Philly ALT.NET meeting about TDD with F# and I see no problem with this at all, and in fact I actively encourage it.  But, you have to think about this in a different light when talking about objects and behaviors, and then turning around to functions and behaviors.

Getting Going with Gallio

As I mentioned last time, Jeff Brown has been hard at work to support the F# community as well.  I was able to get the right build going of Gallio finally after there may have been some mixups with getting the latest code.  Anyhow, I am now able to get these same tests to work, but using MbUnit version 3 and through the Gallio Icarus Runner.  If you're not familiar with Gallio, it is an open platform of tools and runners that is extensible to all testing frameworks.  Jeff Brown talked about it on Hanselminutes with Brad Wilson of xUnit.net fame, Roy Osherove and Charlie Poole of NUnit on the Past, Present and Future of Unit Testing Frameworks.

So, let's just modify the above code to migrate to Gallio with MbUnit version 3 and see how we do:

#light

#R @"D:\Program Files\Gallio\bin\Gallio.dll"
#R @"D:\Program Files\Gallio\bin\MbUnit.dll"

open MbUnit.Framework

let isPrimeNumber(i) =
  let limit = int(sqrt(float(i)))
  let rec check j =
    j > limit or (i % j <> 0 && check(j + 1))
  check 2
   
type System.Int32 with
  member i.IsPrime
    with get () = isPrimeNumber(i)
   
  static member IsPrimeNumber(x) =
    isPrimeNumber(x)

[<Test>]
let IsPrime_WithPrimeNumber_ShouldReturnTrue() =
  Assert.IsTrue((7).IsPrime)
   
[<Test>]
let IsPrime_WithNonPrimeNumber_ShouldReturn_False() =
  Assert.IsFalse((21).IsPrime)
  Assert.IsFalse(System.Int32.IsPrimeNumber(45))
 
And we can notice through the Gallio runner that it's only detecting the MbUnit tests right now, unfortunately.  Hopefully that issue will be resolved soon.



BDD Specs in F#?

F# is a pretty flexible language for unit testing and even BDD style.  I wonder if we could take some lessons from the spec BDD framework for Scala and apply to F#.  Just a thought...

If you're not familiar with specs, it's a BDD framework with some interesting syntax that I'm still coming to terms with.  But the concept looks interesting.  Take a look at a quick example and see if it speaks to you.

package podwysocki.specs

object scalaSpecExample extends Specification {
  "A hello world spec" should {
    "return something" in {
       "hello" mustBe "hello"
    }
  }
}

As I've played around with Scala, this is a pretty interesting concept.  I'm much more a fan of F# as a language, but still there are some interesting pieces to Scala.  I'm also interested in using MSpec from Aaron Jensen at some point, but have a bit on my plate and other points of focus right now. 

Wrapping It Up


In the mean time, we have another testing framework to consider.  Me, personally, I prefer xUnit.net because of the functional aspects of Assert.Throws and so on.  But, that option is up to you quite frankly.  There is a good story to be told here with regards to unit testing and F# that is not to be overlooked.

Published May 29 2008, 02:35 AM by Matthew.Podwysocki
Filed under: ,

Comments

Jim Burger said:

Hi Matt,

I've too have been trying out various BDD semantics in the hope of writing a BDD framework. Lately I've been looking at how I might get something close to Specter (in Boo) Something along the lines of...(forgive any syntax errors)

let at_the_bar() =

 Context "at the bar"

 |> Specify ("when I drink too much I fail", sut,

         fun s -> s.DrinkTenBeers())

 |> Must.Throw (type FailureException)

Hopefully in the next few weeks I'll have something on codeplex for people to try out/modify.

# May 29, 2008 3:13 AM

Jim Burger said:

Thats good news Matt,

I've also been looking at some sort of BDD framework for F#. I like Specter (in Boo) so Im thinking about something like this: (please forgive syntax errors)

let sut = createSUT()

let at_the_bar() =

 Context "at the bar"

 |> Specify ("if I drink too much I fail", sut,

         fun s -> s.DrinkTenBeers())

 |>    Must.Throw (type FailureException)

Any thoughts to this approach?

# May 29, 2008 3:19 AM

Jeff Brown said:

Sorry, I guess I need to upgrade the xUnit.net plugin to the latest version.

You might try just dropping the new xunit.dll into the Gallio bin folder after installation.

# May 29, 2008 4:42 AM

Matthew.Podwysocki said:

@Jeff Brown

I did copy over those xUnit.net dlls and it still didn't register, so I'm not sure what else I'd have to do to get it to work.

Matt

# May 29, 2008 1:30 PM

Matthew.Podwysocki said:

@Jim Burger

Interesting way of tackling the problem.  The forward operator is especially interesting in this case.  I think the syntax can be made a bit more concise though, but I think it's pretty clean.  Definitely throw it out there for public consumption

Matt

# May 29, 2008 6:51 PM

Bruce said:

The link to Gallio is bad - you need to add 'www':

http://www.gallio.com

# May 29, 2008 6:56 PM

Matthew.Podwysocki said:

@Bruce

So noted and fixed

Matt

# May 29, 2008 8:58 PM

Reflective Perspective - Chris Alcock » The Morning Brew #104 said:

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #104

# May 30, 2008 3:35 AM

Matthew Podwysocki said:

As I&#39;ve covered earlier , I&#39;m very interested in the unit testing and behavior testing story

# June 4, 2008 1:05 AM

Matthew Podwysocki's Blog said:

As I've covered earlier , I'm very interested in the unit testing and behavior testing story in F# and

# June 4, 2008 1:10 AM

Community Blogs said:

As I&#39;ve covered earlier , I&#39;m very interested in the unit testing and behavior testing story

# June 4, 2008 1:27 AM

hit said:

thankss

# June 11, 2008 3:29 PM

The ASP.NET MVC Information Portal said:

Pingback from  The ASP.NET MVC Information Portal

# June 17, 2008 2:27 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!

Our Sponsors

Free Tech Publications