Unit testing in F# is a breath of fresh air

I want to start this post off by saying that I was simply blown away with unit testing in F#. Before I go on I want to give reference to the excellent F# for fun and profit blog for getting me started.

Unit testing and F# are a match made in heaven. I think the best thing to do before I go on is to show you a unit test in C#:


public class AllIndexOfTests
{
    [Test]
    public void AllIndexOfhellInHelloHelloIsCorrect()
    {
        var allIndexOf = new AllIndexOf();
        var result = allIndexOf("hello hello", "hello");
        result.SequenceEqual(0, 6).Should().BeTrue();
    }

}

Now in F#:

[<Test>]
    let ``the string 'hello hello' contains the string 'hell' at indexes 0 and 6``() =
        allIndexOf "hello hello" "hell" |> should equal [0; 6]

Check out how the F# code is self describing. Due to the fact that in F# you can put whitespace in a function by escaping the name with the double back tick, the function name can be self describing with spaces which makes it readable. To get the C# code to look as clean as above requires the use of quite a lot of libraries and careful design of your code. Even then you can’t get that close. The F# just reads like English. I would go as far as to say someone who did not understand code could read that test and understand what the function should do.

The testing framework I am using to obtain this syntax is FsUnit. Which is built on top of NUnit. Here are the complete set of tests for the GridSearch solution to the HackerRank problem I went through last time:

module allIndexOf =
    [<Test>]
    let ``the string 'hello hello' contains the string 'hell' at indexes 0 and 6``() =
        allIndexOf "hello hello" "hell" |> should equal [0; 6]

    [<Test>]
    let ``the string 'hello world' does not contain the string 'kevin' ``() =
        allIndexOf "hello world" "kevin" |> should equal []

module find =
    [<Test>]
    let ``the string '123' is in the grid '444 123 444' at [(0,1)]``() =
        find ["444"; "123"; "444"] "123" 0 |> should equal [(0,1)]

    [<Test>]
    let ``the string '123' is in the grid '444123 981231 123122' at [(0,1)]``() =
        find ["444123"; "981231"; "123122"] "123" 0 |> should equal [(3,0); (2,1); (0, 2)]

    [<Test>]
    let ``the string '123' is not in the grid '123 777 444' when the first row is skipped ``() =
        find ["123"; "777"; "444"] "123" 1 |> should equal []

module findExact =
    [<Test>]
    let ``the string '123' is in the grid '444 123 444' is exactly at 0, 1``() =
        findExact ["444"; "123"; "444"] "123" 0 1 |> should equal true

    [<Test>]
    let ``the string '77' is in the grid '9999 9977 0987 0987' is exactly at 2, 1``() =
        findExact ["9999"; "9977"; "0987"; "0987"] "77" 2 1 |> should equal true

    [<Test>]
    let ``the string '865' is not in the grid '9999 9977 0987 0987' is exactly at 2, 1``() =
        findExact ["9999"; "9977"; "0987"; "0987"] "865" 2 1 |> should equal false

    [<Test>]
    let ``the string '77' is not in the grid '9999 9977 0987 0987' is exactly at 3, 3``() =
        findExact ["9999"; "9977"; "0987"; "0987"] "77" 3 3 |> should equal false

module gridContains =
    [<Test>]
    let ``the grid '444 123 444 555' contains the grid '123 444 555 ``() =
        gridContains  ["444"; "123"; "444"; "555"] ["444"; "123"; "444"] |> should equal true

    [<Test>]
    let ``the grid '44488 12311 44490 55598 778899' contains the grid '44 55 ``() =
        gridContains  ["44488"; "12311"; "44490"; "55598"; "778899";] ["44"; "55"] |> should equal true

    [<Test>]
    let ``the grid '44488 12311 44490 55598 778899' does not contain the grid '88 88 ``() =
        gridContains  ["44488"; "12311"; "44490"; "55598"; "778899";] ["88"; "88"] |> should equal false

The fact this fits in such a small space, is succinct and to the point makes it such a good fit for unit testing. I would even argue that even if you use C# for your main application writing your tests in F# could save you time and make your tests much more readable.

If you look at the code listing you will see that I have created the tests all inside the module GridSearchTests. I have then grouped each set of tests under a module that is named the same as the function they are testing. This means in the resharper test runner you get the following:

tests

Which I think is really sweet. Each function is listed along with the test cases that can be read in normal English. Rather than in C# you often name your test cases using camel casing. Meaning that when the test cases become long it can be hard to read them.

To check out the code from this post clone my HackerRankInFSharp repository on github. Please feed back your F# unit testing experiences in the comments.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s