Comparing Discriminated Unions
Asked Answered
L

2

5

I'm a newbie to F# and I'm playing around with FParsec. I would use FParsec to generate an AST. I would like to use FsUnit to write some tests around the various parts of the parser to ensure correct operation.

I'm having a bit of trouble with the syntax (sorry, the exact code is at work, I can post a specific example later) so how exactly could one compare two discriminated unions (one the expected, the other the actual result)? Could someone provide a tiny code example using FsUnit (or NUnit), please?

An example discriminated union (very simple)

type AST = 
    | Variable of string
    | Class of string
    | Number of int
Limen answered 14/9, 2011 at 23:52 Comment(1)
(F# unions have structural equality, which means that = does the right thing, comparing the entire structure/value.)Raybourne
S
6

Since, as Brian pointed out, F# unions have structural equality, this is easy using whichever unit testing framework you are fond of.

FsUnit is an F# specific library built on top of NUnit. My personal favorite F# specific unit testing library is Unquote, ;), which is framework agnostic, working very well with NUnit, xUnit.net, MbUnit, ... or even within FSI. You may be interested in this comparison with FsUnit.

So, how would you do this with NUnit + Unquote? Here's a full working example:

module UnitTests

open NUnit.Framework
open Swensen.Unquote

type AST = 
    | Variable of string
    | Class of string
    | Number of int

let mockFParsec_parseVariable input = Variable(input)

[<Test>]
let ``test variable parse, passing example`` () =
    test <@ mockFParsec_parseVariable "x" = Variable("x") @>

[<Test>]
let ``test variable parse, failing example`` () =
    test <@ mockFParsec_parseVariable "y" = Variable("x") @>

Then running the tests using TestDriven.NET, the output is as follows:

------ Test started: Assembly: xxx.exe ------

Test 'UnitTests.test variable parse, failing example' failed: 

UnitTests.mockFParsec_parseVariable "y" = Variable("x")
Variable "y" = Variable("x")
false
    C:\xxx\UnitTests.fs(19,0): at UnitTests.test variable parse, failing example()

1 passed, 1 failed, 0 skipped, took 0.80 seconds (NUnit 2.5.10).
Sneaky answered 15/9, 2011 at 3:2 Comment(3)
Thank you, I'll give this a try when I get to work. I think I know what I was doing wrong now after seeing your example. I was using (Variable "VAR"), but should have been using Variable("VAR") as my expected ... will mark as answered shortly hopefully!Limen
Worked like a charm, thanks. I'm going to give unquote a hard look because FsUnit just isn't working for me here ...Limen
Unquote is great, loving it. ThanksLimen
T
2

An example - if you want to check the type but not the contents

let matched x= 
    match x with
    |Variable(_) -> true
    | _ -> false

Note here that you need a different function for each element of the discriminated union

If you want to compare equality, you can just do it in the standard way, like

Assert.AreEqual(Variable("hello"),result)

or

if result = Variable("hello") then stuff()
Turnbow answered 15/9, 2011 at 0:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.