将 NUnit 与通用可区分联合一起使用
Using NUnit with generic discriminated unions
我正在尝试使用 FsUnit(在后台使用 NUnit)来测试我的 F# 代码,但它在处理通用可区分联合时遇到了问题。我明白为什么会这样,但我正试图找到一种方法来编写测试而不注释我的期望值。有什么建议吗?是否有更适合此的框架?
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 :(
let expected = None reason
这里,编译器无法知道泛型参数的类型'a
,所以如果使用就在
中使用
NUnit.Framework.Assert.AreEqual(expected,result)
它将等同于 OptionWithReason<object>
的实例,这将不同于 OptionWithReason<int>
的任何实例,例如 result
至于测试框架,你可以试试Expecto。但是,我仍然认为它会带来同样的问题
我想我找到了。 Unquote
似乎有效。我将它与 xUnit 一起使用只是因为它更容易使用 dotnet 核心库进行设置。我只需要导入库并更改断言:
open Xunit
open Swensen.Unquote
[<Fact>]
let testDUComparison () =
test <@ expected = result @>
[<Fact>]
let testDUComparisonExplicit () =
test <@ expectedExplicit = result @>
这种方式回避了这个问题,因为我们使用 F# 的相等性而不是像 OptionWithReason<object>
那样将其传递给 C# 库
您的代码中的部分问题是 Assert.AreEqual
将两个参数作为 obj
,因此编译器不知道类型应该相同 - 如果它知道这一点,那么它会推断 expected
是 int OptionWithReason
类型(与 result
匹配)。
解决这个问题的一个简单方法是为 areEqual
定义一个辅助函数,它接受相同类型的参数:
let areEqual (first:'T) (second:'T) =
NUnit.Framework.Assert.AreEqual(first, second)
现在您可以将您的断言写成:
areEqual expected result
编译器会推断出 expected
和 result
的类型是相同的,它应该可以工作。
我正在尝试使用 FsUnit(在后台使用 NUnit)来测试我的 F# 代码,但它在处理通用可区分联合时遇到了问题。我明白为什么会这样,但我正试图找到一种方法来编写测试而不注释我的期望值。有什么建议吗?是否有更适合此的框架?
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 :(
let expected = None reason
这里,编译器无法知道泛型参数的类型'a
,所以如果使用就在
NUnit.Framework.Assert.AreEqual(expected,result)
它将等同于 OptionWithReason<object>
的实例,这将不同于 OptionWithReason<int>
的任何实例,例如 result
至于测试框架,你可以试试Expecto。但是,我仍然认为它会带来同样的问题
我想我找到了。 Unquote
似乎有效。我将它与 xUnit 一起使用只是因为它更容易使用 dotnet 核心库进行设置。我只需要导入库并更改断言:
open Xunit
open Swensen.Unquote
[<Fact>]
let testDUComparison () =
test <@ expected = result @>
[<Fact>]
let testDUComparisonExplicit () =
test <@ expectedExplicit = result @>
这种方式回避了这个问题,因为我们使用 F# 的相等性而不是像 OptionWithReason<object>
您的代码中的部分问题是 Assert.AreEqual
将两个参数作为 obj
,因此编译器不知道类型应该相同 - 如果它知道这一点,那么它会推断 expected
是 int OptionWithReason
类型(与 result
匹配)。
解决这个问题的一个简单方法是为 areEqual
定义一个辅助函数,它接受相同类型的参数:
let areEqual (first:'T) (second:'T) =
NUnit.Framework.Assert.AreEqual(first, second)
现在您可以将您的断言写成:
areEqual expected result
编译器会推断出 expected
和 result
的类型是相同的,它应该可以工作。