Search code examples
genericsf#nunitdiscriminated-union

Using NUnit with generic discriminated unions


I'm trying to use FsUnit (under the hood it uses NUnit) to test my F# code, but it's having trouble handling generic discriminated unions. I understand why it happens, but I'm trying to find a way to write tests without annotating my expected values. Any advice? Are there maybe frameworks better suited for this?

type OptionWithReason<'a> =
  | Some of 'a
  | None of string

let reason = "division by 0 is not yet supported"
let safeDivide x y = 
    if y = 0 then 
        None reason
    else
        Some(x/y)

let result = safeDivide 1 0

let expected = None reason
let expectedExplicit: int OptionWithReason = None reason

let test1 = result = expected //true
let test2 = result = expectedExplicit //true

NUnit.Framework.Assert.AreEqual(expectedExplicit,result) //pass
NUnit.Framework.Assert.AreEqual(expected,result) //fail :(

Solution

  • A part of the problem in your code is that Assert.AreEqual takes two parameters as obj and so the compiler does not know that the types should be the same - if it knows this, then it would infer that expected is of type int OptionWithReason (to match with result).

    An easy way to fix this is to define a helper function for areEqual that takes parameters of the same type:

    let areEqual (first:'T) (second:'T) = 
      NUnit.Framework.Assert.AreEqual(first, second)
    

    Now you can write your assertion as:

    areEqual expected result
    

    The compiler will infer that the types of expected and result are the same and it should work.