Petrroll
Petrroll

Reputation: 761

Testing collections with FSUnit.Xunit

I'm trying to test equality of two collections in F# using FSUnit (specifically its Xunit branch) but failing horribly so far.

I have a function that returns an array of certain structs and would like to test whether the returned array is correct. The code I'm testing is in C# so it so the function can't return native F# lists.

The most promising approach I've tried is following:

[<Fact>]
let SimpleTest() = 
    let parser = new ExpressionParser()
    parser.ParseExpression "2" |> should equal [new ParsedItem("2", ParsedItemType.Value)]

...but it results in the the test failing because of:

"Message> FSUnit.Xunit+MatchException: Exception of type 'FsUnit.Xunit+MatchException' was thrown. 

Expected value: Equals [(2)]
Actual: was [2]

I can see that it's because the type of native F# list doesn't match a native array but have honestly no idea (nor have I found anything in documentation) how to do it differently (other then creating native array beforehand and populating it one by one...).

I've also tried some other approaches but they usually wouldn't even compile.


PS: I'm completely new to both F# and Xunit so I might be missing something absolutely obvious.

EDIT: A workaround that actually works better was suggested in comments (comparing string representations instead of the objects themselves) and while I will use that in my actual code I'd still appreciate a true solution to my problem above.

Upvotes: 2

Views: 1138

Answers (2)

Petrroll
Petrroll

Reputation: 761

Ok, I've found the answer and it's simpler than I thought it'd be. First off the assentation works well the problem was in syntax and me not bothering to read the documentation on how to create an array in F# and just guessing it.

There were two things wrong. First [new ParsedItem("2", ParsedItemType.Value)] doesn't create an array it creates a list. That in itself wouldn't be a problem for FSUnit's should equal but it's enough to make simple structural equality test using = fail.

The second thing that was wrong was that I didn't really compare with [new ParsedItem("2", ParsedItemType.Value)] I compared with [new ParsedItem("2", ParsedItemType.Value), new ParsedItem("+", ParsedItemType.Operator), new ParsedItem("3", ParsedItemType.Value)] and that actually creates a list containing one touple. And that - unsurprisingly - didn't assert well :).

Simply reading the documentation and learning that an array is supposed to be created [|new ParsedItem("2", ParsedItemType.Value); new ParsedItem("+", ParsedItemType.Operator); new ParsedItem("3", ParsedItemType.Value)|] fixed the issue.


Anyway, thanks for the comments and the other answer. Though they didn't answer my question they increased my knowledge about F# and gave me a new idea how to test :).

Upvotes: 2

Mark Seemann
Mark Seemann

Reputation: 233150

Although you can't easily return F# lists from your C# code, one option is to return arrays. These have structural equality, so you can simply compare them to determine if they are equal to each other:

open System.Linq

let csharpArray = Enumerable.Range(0, 10).ToArray()
let fsharpArray = [| 0..9 |]

These two arrays are equal:

> csharpArray = fsharpArray;;
val it : bool = true

If you don't want to return arrays, you can also return IEnumerable<T>, and convert to either lists or arrays in F#:

> let csharpEnumerable = Enumerable.Range(0, 10);;    
val csharpEnumerable : System.Collections.Generic.IEnumerable<int>

> csharpEnumerable |> Seq.toList = [0..9];;
val it : bool = true

For a more comprehensive to introduction to unit testing with F#, you may want to view my Pluralsight course on the topic.

Upvotes: 3

Related Questions