Monday, December 14, 2009

Towards FsUnit 1.0

I have been giving a lot of consideration recently to an FsUnit 1.0 release and the direction of the project. The 0.6 release was meant to steer the project more in the direction of Behavioral-Driven Development but there is already a much better project out there for F# and BDD, NaturalSpec.

FsUnit 1.0 will instead be geared for more classical unit-testing and it now has two explicit goals: 1) to make unit-testing with F# more functional in nature and 2) to leverage existing unit-testing frameworks while at the same time exploring new possibilities offered by the F# language.

The target audience for this project is the F# developer (new and veteran alike) who wishes to use the same unit-testing framework that they’re already knowledgeable about: NUnit, MbUnit, xUnit, and MsTest. The new 0.9 release supports only NUnit but the others will be added soon.

The core syntax is pretty much the same as it has always been:

1 |> should equal 1

1 |> should not (equal 2)

[1] |> should contain 1

true |> should be True

But tests are once again contained within a test fixture and executed with a test runner. Here is the code for one of the project examples (UPDATE: removed non-standard use of self-identifier per reader's comments. Thanks, Alan!):

type LightBulb(state) =
member x.On = state
override x.ToString() =
match x.On with
| true -> "On"
| false -> "Off"

[<TestFixture>]
type ``Given a LightBulb that has had its state set to true`` ()=
let lightBulb = new LightBulb(true)

[<Test>] member test.
``when I ask whether it is On it answers true.`` ()=
lightBulb.On |> should be True

[<Test>] member test.
``when I convert it to a string it becomes "On".`` ()=
string lightBulb |> should equal "On"

[<TestFixture>]
type ``Given a LightBulb that has had its state set to false`` ()=
let lightBulb = new LightBulb(false)

[<Test>] member test.
``when I ask whether it is On it answers false.`` ()=
lightBulb.On |> should be False

[<Test>] member test.
``when I convert it to a string it becomes "Off".`` ()=
string lightBulb |> should equal "Off"

I’m curious as to what people think about the use of back-ticked method names. I, for one, find it very helpful to be able to write in plain prose instead of CamelCase’d or snake_case’d method names.

Stay tuned to this blog for more information as FsUnit reaches a 1.0 release.

6 comments:

Adam Cooper said...

I haven't used it yet, but I find the backtick naming very attractive (not to mention extremely clever--it took me a while to understand how this is understood by the F# compiler).

I'm going to download 0.9 today and start using it as soon as I get a chance.

Keep up the good work.

Ray Vernagus said...

@Adam: Thanks! I'll look forward to any feedback that you may have.

Adam Cooper said...

Hey Ray,

What is your preferred way of running NUnit tests you've written in F#?

It looks like the NUnit GUI test runner only picks up on the class name and member name, ignoring the self identifier (which doesn't surprise me).

With that it mind, I'm wonder if:

x.``When something happens then something should be verified``

makes more sense to use than

``When something happens``.``then something should be verified``

What are your thoughts?

Ray Vernagus said...

@Adam: That's an excellent point that I hadn't thought of. Any text contained in the self-identifier portion of a member declaration will not appear in test failure messages which leads to very unhelpful messages. I agree, it's better to not use the self-identifier in this way. I'm going to change my post and the project accordingly.

I appreciate the feedback!

Thorsten Lorenz said...

Since the 0.9 release is a totally new implementation and has no "specs" etc. you should probably point out, that the 5min tutorial doesn't apply to this new version.

I got somewhat confused and others might too.

Ray Vernagus said...

@Thorsten: Thanks for the reminder. I've been meaning to get to that. I'll make the updates ASAP.