FsUnit


What is 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, xUnit, MbUnit, 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.

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

Syntax

With FsUnit, you can write unit tests like this:

1: 
2: 
open NUnit.Framework
open FsUnit

One object equals or does not equal another:

1: 
2: 
1 |> should equal 1
1 |> should not' (equal 2)

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

1: 
2: 
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:

1: 
2: 
3: 
4: 
5: 
6: 
"ships" |> should startWith "sh"
"ships" |> should not' (startWith "ss")
"ships" |> should endWith "ps"
"ships" |> should not' (endWith "ss")
"ships" |> should haveSubstring "hip"
"ships" |> should not' (haveSubstring "pip")

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

1: 
2: 
[1] |> should contain 1
[] |> should not' (contain 1)

A List or Array instance has a certain length:

1: 
anArray |> should haveLength 4

A Collection instance has a certain count:

1: 
aCollection |> should haveCount 4

A function should throw a certain type of exception:

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

A function should fail

1: 
shouldFail (fun () -> 5/0 |> ignore)

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

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
true |> should be True
false |> should not' (be True)

"" |> should be EmptyString
"" |> should be NullOrEmptyString

null |> should be NullOrEmptyString
null |> should be Null
null |> should be null

anObj |> should not' (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>)

Choice<int, string>.Choice1Of2(42) |> should be (choice 1)

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

"test" |> should be instanceOfType<string>
"test" |> should not' (be instanceOfType<int>)

2.0 |> should not' (be NaN)

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

[1;2;3] |> should be ascending
[1;3;2] |> should not' (be ascending)
[3;2;1] |> should be descending
[3;1;2] |> should not' (be descending)

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 in the NuGet documentation.

Test Projects Targeting Higher F# Runtimes

If you build your test project with a target F# runtime greater than the targeted runtime of the FsUnit assembly, you may find FsUnit operators failing at runtime, in which case you need to add a binding redirect to the App.config file.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-999.999.999.999" newVersion="4.4.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Contributing

The project is hosted on GitHub where you can report issues, fork the project and submit pull requests. If you're adding a new public API, please also consider adding samples that can be turned into a documentation. You might also want to read the library design notes to understand how it works.

namespace NUnit
namespace NUnit.Framework
namespace FsUnit
val should : f:('a -> #Constraints.Constraint) -> x:'a -> y:obj -> unit

Full name: FsUnit.TopLevelOperators.should
val equal : x:'a -> Constraints.EqualConstraint

Full name: FsUnit.TopLevelOperators.equal
val not' : x:Constraints.IConstraint -> Constraints.NotConstraint

Full name: FsUnit.TopLevelOperators.not'
val equalWithin : tolerance:'a -> x:'b -> Constraints.EqualConstraint

Full name: FsUnit.TopLevelOperators.equalWithin
val startWith : s:string -> Constraints.StartsWithConstraint

Full name: FsUnit.TopLevelOperators.startWith
val endWith : s:string -> Constraints.EndsWithConstraint

Full name: FsUnit.TopLevelOperators.endWith
val haveSubstring : s:string -> Constraints.SubstringConstraint

Full name: FsUnit.TopLevelOperators.haveSubstring
val contain : x:'a -> Constraints.ContainsConstraint

Full name: FsUnit.TopLevelOperators.contain
val haveLength : n:'a -> Constraints.EqualConstraint

Full name: FsUnit.TopLevelOperators.haveLength
val haveCount : n:'a -> Constraints.EqualConstraint

Full name: FsUnit.TopLevelOperators.haveCount
val failwith : message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.failwith
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
val throw : arg00:System.Type -> Constraints.ExactTypeConstraint

Full name: FsUnit.TopLevelOperators.throw
val typeof<'T> : System.Type

Full name: Microsoft.FSharp.Core.Operators.typeof
namespace System
Multiple items
type Exception =
  new : unit -> Exception + 2 overloads
  member Data : IDictionary
  member GetBaseException : unit -> Exception
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member GetType : unit -> Type
  member HelpLink : string with get, set
  member InnerException : Exception
  member Message : string
  member Source : string with get, set
  member StackTrace : string
  ...

Full name: System.Exception

--------------------
System.Exception() : unit
System.Exception(message: string) : unit
System.Exception(message: string, innerException: exn) : unit
val throwWithMessage : m:string -> t:System.Type -> Constraints.EqualConstraint

Full name: FsUnit.TopLevelOperators.throwWithMessage
val shouldFail : f:(unit -> unit) -> unit

Full name: FsUnit.TopLevelOperators.shouldFail
val be : ('a -> 'a)

Full name: FsUnit.TopLevelOperators.be
val True : Constraints.TrueConstraint

Full name: FsUnit.TopLevelOperators.True
val EmptyString : Constraints.EmptyStringConstraint

Full name: FsUnit.TopLevelOperators.EmptyString
val NullOrEmptyString : Constraints.OrConstraint

Full name: FsUnit.TopLevelOperators.NullOrEmptyString
val Null : Constraints.NullConstraint

Full name: FsUnit.TopLevelOperators.Null
val sameAs : x:'a -> Constraints.SameAsConstraint

Full name: FsUnit.TopLevelOperators.sameAs
val greaterThan : x:'a -> Constraints.GreaterThanConstraint

Full name: FsUnit.TopLevelOperators.greaterThan
val greaterThanOrEqualTo : x:'a -> Constraints.GreaterThanOrEqualConstraint

Full name: FsUnit.TopLevelOperators.greaterThanOrEqualTo
val lessThan : x:'a -> Constraints.LessThanConstraint

Full name: FsUnit.TopLevelOperators.lessThan
val lessThanOrEqualTo : x:'a -> Constraints.LessThanOrEqualConstraint

Full name: FsUnit.TopLevelOperators.lessThanOrEqualTo
val ofExactType<'a> : Constraints.ExactTypeConstraint

Full name: FsUnit.TopLevelOperators.ofExactType
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
type obj = System.Object

Full name: Microsoft.FSharp.Core.obj
Multiple items
type Choice<'T1,'T2> =
  | Choice1Of2 of 'T1
  | Choice2Of2 of 'T2

Full name: Microsoft.FSharp.Core.Choice<_,_>

--------------------
type Choice<'T1,'T2,'T3> =
  | Choice1Of3 of 'T1
  | Choice2Of3 of 'T2
  | Choice3Of3 of 'T3

Full name: Microsoft.FSharp.Core.Choice<_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4> =
  | Choice1Of4 of 'T1
  | Choice2Of4 of 'T2
  | Choice3Of4 of 'T3
  | Choice4Of4 of 'T4

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5> =
  | Choice1Of5 of 'T1
  | Choice2Of5 of 'T2
  | Choice3Of5 of 'T3
  | Choice4Of5 of 'T4
  | Choice5Of5 of 'T5

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5,'T6> =
  | Choice1Of6 of 'T1
  | Choice2Of6 of 'T2
  | Choice3Of6 of 'T3
  | Choice4Of6 of 'T4
  | Choice5Of6 of 'T5
  | Choice6Of6 of 'T6

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_,_>

--------------------
type Choice<'T1,'T2,'T3,'T4,'T5,'T6,'T7> =
  | Choice1Of7 of 'T1
  | Choice2Of7 of 'T2
  | Choice3Of7 of 'T3
  | Choice4Of7 of 'T4
  | Choice5Of7 of 'T5
  | Choice6Of7 of 'T6
  | Choice7Of7 of 'T7

Full name: Microsoft.FSharp.Core.Choice<_,_,_,_,_,_,_>
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
val choice : n:int -> ChoiceConstraint

Full name: FsUnit.TopLevelOperatorsExtra.choice
val Empty : Constraints.EmptyConstraint

Full name: FsUnit.TopLevelOperators.Empty
val instanceOfType<'a> : Constraints.InstanceOfTypeConstraint

Full name: FsUnit.TopLevelOperators.instanceOfType
val NaN : Constraints.NaNConstraint

Full name: FsUnit.TopLevelOperators.NaN
val unique : Constraints.UniqueItemsConstraint

Full name: FsUnit.TopLevelOperators.unique
val ascending : Constraints.CollectionOrderedConstraint

Full name: FsUnit.TopLevelOperators.ascending
val descending : Constraints.CollectionOrderedConstraint

Full name: FsUnit.TopLevelOperators.descending
Fork me on GitHub