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, and MsTest.
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:
With FsUnit, you can write unit tests like this:
open NUnit.Framework
open FsUnit
One object equals or does not equal another:
1 |> should equal 1
1 |> should not' (equal 2)
One sequence equals or does not equal another:
seq { 1; 2; 3 } |> should equalSeq (seq { 1; 2; 3 })
seq { 1 } |> should not' (equalSeq (seq { 1; 2}))
One collection is equivalent or is not equivalent to another (order doesn't matter):
[2;4;6] |> should equivalent [4;6;2]
[2;4;6] |> should not' (equivalent [4;8;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")
"ships" |> should haveSubstring "hip"
"ships" |> should not' (haveSubstring "pip")
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:
anArray |> should haveLength 4
A Collection instance has a certain count:
aCollection |> should haveCount 4
A function should throw a certain type of exception:
(fun () -> failwith "BOOM!" |> ignore) |> should throw typeof<System.Exception>
(fun () -> failwith "BOOM!" |> ignore) |> should (throwWithMessage "BOOM!") typeof<System.Exception>
A function should fail
shouldFail (fun () -> 5/0 |> ignore)
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
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>)
[] |> 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
[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)
[1..10] |> should be (supersetOf [3;6;9])
[1..10] |> should not' (be supersetOf [5;11;21])
[3;6;9] |> should be (subsetOf [1..10])
[5;11;21] |> should not' (be subsetOf [1..10])
The ofCase operator allows you to check the case of a union.
Supplying an expression that will result in a non-union type as well as supplying a non-union type as value argument will result in an exception detailing which parameter is wrong. Note that the actual value of the case is NOT checked, e.g. using <@ MyCase 5 @>
as expression and (MyCase 10)
as parameter will succeed. It is possible to check for more than one case by using a tuple of union cases.
type TestUnion = First | Second of int | Third of string
First |> should be (ofCase<@ First @>)
First |> should be (ofCase<@ First, Second @>) // checks if on the cases matches the given case
Second 5 |> should be (ofCase<@ Second 10 @>) // note, the actual value is not checked!
First |> should not' (be ofCase<@ Second 5 @>)
5 |> should be (ofCase<@ Second 5 @>) // will throw an exception
Second 5 |> should be (ofCase<@ int @>) // will throw an exception
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.
<?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>
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 FsUnit
val anArray: 'a list
val aCollection: System.Collections.Generic.List<int>
Namespace System
Namespace System.Collections
Namespace System.Collections.Generic
Multiple items
type List<'T> =
interface ICollection<'T>
interface IEnumerable<'T>
interface IEnumerable
interface IList<'T>
interface IReadOnlyCollection<'T>
interface IReadOnlyList<'T>
interface ICollection
interface IList
new: unit -> unit + 2 Überladungen
member Add: item: 'T -> unit
...
<summary>Represents a strongly typed list of objects that can be accessed by index. Provides methods to search, sort, and manipulate lists.</summary>
<typeparam name="T">The type of elements in the list.</typeparam>
--------------------
System.Collections.Generic.List() : System.Collections.Generic.List<'T>
System.Collections.Generic.List(collection: System.Collections.Generic.IEnumerable<'T>) : System.Collections.Generic.List<'T>
System.Collections.Generic.List(capacity: int) : System.Collections.Generic.List<'T>
Multiple items
val int: value: 'T -> int (requires member op_Explicit)
<summary>Converts the argument to signed 32-bit integer. This is a direct conversion for all
primitive numeric types. For strings, the input is converted using <c>Int32.Parse()</c>
with InvariantCulture settings. Otherwise the operation requires an appropriate
static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted int</returns>
<example id="int-example"><code lang="fsharp"></code></example>
--------------------
[<Struct>]
type int = int32
<summary>An abbreviation for the CLI type <see cref="T:System.Int32" />.</summary>
<category>Basic Types</category>
--------------------
type int<'Measure> =
int
<summary>The type of 32-bit signed integer numbers, annotated with a unit of measure. The unit
of measure is erased in compiled code and when values of this type
are analyzed using reflection. The type is representationally equivalent to
<see cref="T:System.Int32" />.</summary>
<category>Basic Types with Units of Measure</category>
val anObj: obj
type obj = System.Object
<summary>An abbreviation for the CLI type <see cref="T:System.Object" />.</summary>
<category>Basic Types</category>
val otherObj: obj
Namespace NUnit
Namespace NUnit.Framework
val should: f: ('a -> #Constraints.Constraint) -> x: 'a -> actual: obj -> unit
val equal: expected: 'a -> Constraints.EqualConstraint (requires equality)
Multiple items
val seq: sequence: seq<'T> -> seq<'T>
<summary>Builds a sequence using sequence expression syntax</summary>
<param name="sequence">The input sequence.</param>
<returns>The result sequence.</returns>
<example id="seq-cast-example"><code lang="fsharp">
seq { for i in 0..10 do yield (i, i*i) }
</code></example>
--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>
<summary>An abbreviation for the CLI type <see cref="T:System.Collections.Generic.IEnumerable`1" /></summary>
<remarks>
See the <see cref="T:Microsoft.FSharp.Collections.SeqModule" /> module for further operations related to sequences.
See also <a href="https://docs.microsoft.com/dotnet/fsharp/language-reference/sequences">F# Language Guide - Sequences</a>.
</remarks>
val equalSeq: expected: seq<'a> -> Constraints.EqualConstraint
val equivalent: expected: System.Collections.IEnumerable -> Constraints.CollectionEquivalentConstraint
val equalWithin: tolerance: 'a -> expected: 'b -> Constraints.EqualConstraint (requires equality)
val startWith: expected: string -> Constraints.StartsWithConstraint
val endWith: expected: string -> Constraints.EndsWithConstraint
val haveSubstring: expected: string -> Constraints.SubstringConstraint
val contain: expected: 'a -> Constraints.ContainsConstraint
val haveLength: expected: 'a -> Constraints.EqualConstraint
val haveCount: expected: 'a -> Constraints.EqualConstraint
val failwith: message: string -> 'T
<summary>Throw a <see cref="T:System.Exception" /> exception.</summary>
<param name="message">The exception message.</param>
<returns>Never returns.</returns>
<example id="failwith-example"><code lang="fsharp">
let failingFunction() =
failwith "Oh no" // Throws an exception
true // Never reaches this
failingFunction() // Throws a System.Exception
</code></example>
val ignore: value: 'T -> unit
<summary>Ignore the passed value. This is often used to throw away results of a computation.</summary>
<param name="value">The value to ignore.</param>
<example id="min-example"><code lang="fsharp">
ignore 55555 // Evaluates to ()
</code></example>
val throw: arg00: System.Type -> Constraints.ExactTypeConstraint
val typeof<'T> : System.Type
<summary>Generate a System.Type runtime representation of a static type.</summary>
<example id="typeof-example"><code lang="fsharp">
let t = typeof<int> // Gets the System.Type
t.FullName // Evaluates to "System.Int32"
</code></example>
Multiple items
type Exception =
interface ISerializable
new: unit -> unit + 2 Überladungen
member GetBaseException: unit -> exn
member GetObjectData: info: SerializationInfo * context: StreamingContext -> unit
member GetType: unit -> Type
member ToString: unit -> string
member Data: IDictionary
member HResult: int
member HelpLink: string
member InnerException: exn
...
<summary>Represents errors that occur during application execution.</summary>
--------------------
System.Exception() : System.Exception
System.Exception(message: string) : System.Exception
System.Exception(message: string, innerException: exn) : System.Exception
val throwWithMessage: expected: string -> t: System.Type -> Constraints.EqualConstraint
val shouldFail: f: (unit -> unit) -> unit
val be: ('a -> 'a)
val True: Constraints.TrueConstraint
val EmptyString: Constraints.EmptyStringConstraint
val NullOrEmptyString: Constraints.OrConstraint
val Null: Constraints.NullConstraint
val sameAs: expected: 'a -> Constraints.SameAsConstraint
val greaterThan: expected: 'a -> Constraints.GreaterThanConstraint
val greaterThanOrEqualTo: expected: 'a -> Constraints.GreaterThanOrEqualConstraint
val lessThan: expected: 'a -> Constraints.LessThanConstraint
val lessThanOrEqualTo: expected: 'a -> Constraints.LessThanOrEqualConstraint
val ofExactType<'a> : Constraints.ExactTypeConstraint
Multiple items
val float: value: 'T -> float (requires member op_Explicit)
<summary>Converts the argument to 64-bit float. This is a direct conversion for all
primitive numeric types. For strings, the input is converted using <c>Double.Parse()</c>
with InvariantCulture settings. Otherwise the operation requires an appropriate
static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted float</returns>
<example id="float-example"><code lang="fsharp"></code></example>
--------------------
[<Struct>]
type float = System.Double
<summary>An abbreviation for the CLI type <see cref="T:System.Double" />.</summary>
<category>Basic Types</category>
--------------------
type float<'Measure> =
float
<summary>The type of double-precision floating point numbers, annotated with a unit of measure.
The unit of measure is erased in compiled code and when values of this type
are analyzed using reflection. The type is representationally equivalent to
<see cref="T:System.Double" />.</summary>
<category index="6">Basic Types with Units of Measure</category>
val Empty: Constraints.EmptyConstraint
val instanceOfType<'a> : Constraints.InstanceOfTypeConstraint
Multiple items
val string: value: 'T -> string
<summary>Converts the argument to a string using <c>ToString</c>.</summary>
<remarks>For standard integer and floating point values the and any type that implements <c>IFormattable</c><c>ToString</c> conversion uses <c>CultureInfo.InvariantCulture</c>. </remarks>
<param name="value">The input value.</param>
<returns>The converted string.</returns>
<example id="string-example"><code lang="fsharp"></code></example>
--------------------
type string = System.String
<summary>An abbreviation for the CLI type <see cref="T:System.String" />.</summary>
<category>Basic Types</category>
val NaN: Constraints.NaNConstraint
val unique: Constraints.UniqueItemsConstraint
val ascending: Constraints.CollectionOrderedConstraint
val descending: Constraints.CollectionOrderedConstraint
val supersetOf: expected: System.Collections.IEnumerable -> Constraints.CollectionSupersetConstraint
val subsetOf: expected: System.Collections.IEnumerable -> Constraints.CollectionSubsetConstraint
type TestUnion =
| First
| Second of int
| Third of string
Union-Fall TestUnion.First: TestUnion
Union-Fall TestUnion.Second: int -> TestUnion
Union-Fall TestUnion.Third: string -> TestUnion
val ofCase: case: Quotations.Expr -> CustomConstraints.OfSameCaseConstraint