Unit testing: '[] |> should equal List.empty' is not working as expected

633 Views Asked by At

I have the following code with a test that fails:

open Xunit
open FsUnit.Xunit

let rec openOrSenior xs = 
    match xs with
    | head :: tail when fst head >= 55 && snd head >= 7 -> "Senior" :: openOrSenior tail
    | head :: tail -> "Open" :: openOrSenior tail
    | [] -> []

[<Fact>]
let ``empty input gives empty result``() =
    openOrSenior [] |> should equal List.empty

The test fails with the following matching error

FsUnit.Xunit+MatchException : Exception of type 'FsUnit.Xunit+MatchException' was thrown. Expected: Equals []
Actual: was []

2

There are 2 best solutions below

0
On BEST ANSWER

equal in FsUnit does some fancy match were be is just identity function. Here is the link source

Your check will be fine if you use:

|> should be Empty
2
On

This answer is just to clarify the reasons behind this. It turned out to be too long for a comment.

This is a type mismatch situation. The two values [] and [] look the same when printed out, but actually have different types: the "actual" value is string list, but the "expected" value is obj list.

This happens because List is generic, and should equal doesn't require that "expected" and "actual" have the same type, thus preventing type inference from kicking in. For example, this compiles:

5 |> should equal "abc"

It will, of course, fail at runtime, nicely showing you that the values are not, in fact, equal.

But if one of your values is generic in return type:

let a: int list = []
a |> should equal []

then the lack of type inference means that this value will end up having type obj, and thus not strictly speaking "equal" to the other value, which has a different type.