Geert Van Laethem
Geert Van Laethem

Reputation: 737

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

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 []

Upvotes: 4

Views: 658

Answers (2)

Fyodor Soikin
Fyodor Soikin

Reputation: 80754

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.

Upvotes: 9

Bartek Kobyłecki
Bartek Kobyłecki

Reputation: 2395

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

Upvotes: 9

Related Questions