Skip to content

PatrickMcDonald/FsUnit

 
 

Repository files navigation

FsUnit

FsUnit is a set of libraries that makes unit-testing with F# more enjoyable. It adds a special syntax to your favorite .NET testing framework. FsUnit currently supports NUnit, MbUnit, xUnit, and MsTest (VS11 only).

The goals of FsUnit are:

  • to make unit-testing feel more at home in F# , i.e., more functional.
  • to leverage existing test frameworks while at the same time adapting them to the F# language in new ways.

Syntax

With FsUnit, you can write unit tests like this:

One object equals or does not equal another:

1 |> should equal 1

1 |> should not' (equal 2)

One numeric object equals or does not equal another, with a specified tolerance:

10.1 |> should (equalWithin 0.1) 10.11

10.1 |> should not' ((equalWithin 0.001) 10.11)

A string does or does not start with or end with a specified substring:

"ships" |> should startWith "sh"

"ships" |> should not' (startWith "ss")

"ships" |> should endWith "ps"

"ships" |> should not' (endWith "ss")

A List, Seq, or Array instance contains or does not contain a value:

[1] |> should contain 1

[] |> should not' (contain 1)

A List or Array instance has a certain length (NUnit only):

anArray |> should haveLength 4

A Collection instance has a certain count (NUnit only):

aCollection |> should haveCount 4

A function should throw a certain type of exception:

(fun () -> failwith "BOOM!" |> ignore) |> should throw typeof<System.Exception>

A number of assertions can be created using the be keyword:

true |> should be True

false |> should not' (be True)

"" |> should be EmptyString

"" |> should be NullOrEmptyString

null |> should be NullOrEmptyString

null |> should be Null

anObj |> should not' (be Null)

anObj |> should be (sameAs anObj)

anObj |> should not' (be sameAs otherObj)

11 |> should be (greaterThan 10)

9 |> should not' (be greaterThan 10)

11 |> should be (greaterThanOrEqualTo 10)

9 |> should not' (be greaterThanOrEqualTo 10)

10 |> should be (lessThan 11)

10 |> should not' (be lessThan 9)

10.0 |> should be (lessThanOrEqualTo 10.1)

10 |> should not' (be lessThanOrEqualTo 9)

0.0 |> should be ofExactType<float>

1 |> should not' (be ofExactType<obj>)

[] |> should be Empty // NUnit only

[1] |> should not' (be Empty) // NUnit only

"test" |> should be instanceOfType<string> // Currently, NUnit only and requires version 1.0.1.0+

"test" |> should not' (be instanceOfType<int>) // Currently, NUnit only and requires version 1.0.1.0+
	
2.0 |> should not' (be NaN) // Currently, NUnit only and requires version 1.0.1.0+

[1;2;3] |> should be unique // Currently, NUnit only and requires version 1.0.1.0+

Depricated Functions

Prior to version 1.1.0.0, FsUnit implemented a function named "not" that overwrote the F# operator of the same name. This is not ideal, so as of version 1.1.0.0 the FsUnit function has been renamed to "not'" (not + single-quote). If you need or want the previous function, it can be made available by opening the FsUnitDepricated module.

Visual Studio 11 Support

Visual Studio 11 support is available for all 4 of the targetted testing frameworks. FsUnit.MsTest is supported only in VS11 and no additional steps are required to use it. FsUnit for NUnit, FsUnit.MbUnit, and FsUnit.xUnit target F# 2.0 as well as F# 3.0. Because of this, a few additional steps are required in order to use these libraries in VS11. After installing one of these packages, add an App.config file to the project (if one doesn't already exist). Build the project and then run the command "Add-BindingRedirect projectname" (where projectname is the name of your test project) in the NuGet Package Manager Console. This command will update the App.config to include binding redirects from previous version of FSharp.Core to FSharp.Core version 4.3.0.0. More information about this command can be found at http://docs.nuget.org/docs/reference/package-manager-console-powershell-reference.

NuGet

NuGet packages are available for each of the supported testing frameworks:

  • The package with ID FsUnit supports NUnit. It is the original.
  • The package with ID FsUnit.xUnit supports xUnit.NET.
  • The package with ID FsUnit.MbUnit supports MbUnit.
  • The packager with ID Fs30Unit.MsTest supports MsTest in VS11.

Examples

The following are examples of FsUnit with MbUnit, xUnit, and NUnit respectively:

MbUnit:

module Test.``Project Euler - Problem 1``

open MbUnit.Framework
open FsUnit.MbUnit

let GetSumOfMultiplesOf3And5 max =  
    seq{3..max-1} |> Seq.fold(fun acc number ->  
                        (if (number % 3 = 0 || number % 5 = 0) then   
                            acc + number else acc)) 0 

[<Test>]
let ``When getting sum of multiples of 3 and 5 to a max number of 10 it should return a sum of 23`` () =  
    GetSumOfMultiplesOf3And5(10) |> should equal 23 

xUnit (Thanks to Keith Nicholas and "Julian" from hubFS for this example! http://cs.hubfs.net/forums/thread/3938.aspx):

module BowlingGame.``A game of bowling``

open Xunit
open FsUnit.Xunit

let (|EndOfGame|IncompleteStrike|Strike|Normal|Other|) (l, frame) =
    match l with
    | _ when frame = 11            -> EndOfGame(0)
    | [10;s]                       -> IncompleteStrike(10+s+s)
    | 10::s::n::tail               -> Strike(10+s+n, s::n::tail)
    |  f::s::n::tail when f+s = 10 -> Normal(f+s+n,  n::tail)
    |  f::s::n::tail               -> Normal(f+s,    n::tail)
    | ls                           -> Other(List.fold (+) 0 ls)

let scoreBowls bowls =
    let rec scoreBowls' frame l current_score =
        let nextframe = scoreBowls' (frame+1)
        match (l, frame) with
        | EndOfGame(score)        -> current_score + score
        | IncompleteStrike(score) -> current_score + score
        | Strike(score, l)        -> nextframe l (current_score + score)
        | Normal(score, l)        -> nextframe l (current_score + score)
        | Other(score)            -> current_score + score
    scoreBowls' 1 bowls 0

[<Fact>] 
let ``with simple scores should get the expected score.`` () =
    scoreBowls [1;2;3] |> should equal 6

[<Fact>]
let ``with a spare should get the expected score (spare).`` () =
    scoreBowls [2;8;1] |> should equal 12

[<Fact>]
let ``with a strike should get the expected score (strike).`` () =
    scoreBowls [10;1;2] |> should equal 16

[<Fact>]
let ``that is perfect should get a score of 300.``() =
    scoreBowls [for i in 1..18 -> 10] |> should equal 300

[<Fact>]
let ``with spares in the last frame should get the expected score (spare in last frame).`` () =
    scoreBowls ([for i in 1..18 -> 0] @ [2;8;1]) |> should equal 11

[<Fact>]
let ``with a strike in the last frame should get the expected score (strike in last frame).`` () =
    scoreBowls ([for i in 1..18 -> 0] @ [10;10;1]) |> should equal 21

[<Fact>] 
let ``with double strikes should add the score of the first strike to the score of the second.`` () =
    scoreBowls [10;10;1] |> should equal 33

[<Fact>]
let ``that looks like an average bowler's game should get the expected score (example game).`` () =
    scoreBowls [1;4;4;5;6;4;5;5;10;0;1;7;3;6;4;10;2;8;6] |> should equal 133

NUnit (Note: NUnit can also be utilized without specifying a type as in the examples for MbUnit and xUnit):

namespace LightBulb.Tests

open NUnit.Framework
open FsUnit

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 x.
     ``when I ask whether it is On it answers true.`` ()=
            lightBulb.On |> should be True

    [<Test>] member x.
     ``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 x.
     ``when I ask whether it is On it answers false.`` ()=
            lightBulb.On |> should be False

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

Getting Involved

GitHub makes collaboration very easy. To get involved with FsUnit, simply follow the directions provided by GitHub to fork this repository, then implement lots of cool stuff, and finally send a pull request.

A few things to keep in mind:

  • Going forward, FsUnit will aim to support as much functionality as possible across all support testing frameworks.

  • Development environments need to be setup to run tests for MbUnit, xUnit.NET and NUnit. A product like Resharper can make this easier.

  • Since the unit tests for FsUnit are written with FsUnit, failing tests are just as important as passing tests.

Release Notes

  • 1.1.0.0 - Pulls in the latest versions for xUnit.NET and NUnit. Replaces the "not" keyword with "not'" and adds the FsUnitDepricated module for backward compatibility. Adds MsTest support for VS11 only.
  • 1.0.1.3 - Includes new assertions for NUnit such as NaN, instanceOfType, and unique.
  • 1.0.0.4 - Added added support for xUnit.NET and MbUnit and a new assertion.
  • 0.9.1.1 - Added several new assertions.
  • 0.9.0.0 - Ray Vernagus built this version and several before it with NUnit as the targeted testing framework.

About

FsUnit makes unit-testing with F# more enjoyable. It adds a special syntax to your favorite .NET testing framework.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published