F# 如何与FsUnit一起检查歧视工会的情况?
我想检查一个值是否属于歧视联合的特定情况,而不必检查任何包含的数据。我的动机是在每个单元测试中只测试一件事情 示例如下(最后两行给出了编译错误):F# 如何与FsUnit一起检查歧视工会的情况?,f#,discriminated-union,fsunit,F#,Discriminated Union,Fsunit,我想检查一个值是否属于歧视联合的特定情况,而不必检查任何包含的数据。我的动机是在每个单元测试中只测试一件事情 示例如下(最后两行给出了编译错误): 模块MyState 打开NUnit.Framework 开放式FSU MyState类型= |国家一号 |int的状态二 让增量状态= 匹配状态 |当n=10时状态一n->状态二0 |StateOne n->StateOne(n+1) |状态二n->状态二(n+1) [] 让``递增StateOne 10产生一个StateTwo`()= 让state
模块MyState
打开NUnit.Framework
开放式FSU
MyState类型=
|国家一号
|int的状态二
让增量状态=
匹配状态
|当n=10时状态一n->状态二0
|StateOne n->StateOne(n+1)
|状态二n->状态二(n+1)
[]
让``递增StateOne 10产生一个StateTwo`()=
让state=StateOne 10
(增量状态)|>应等于(状态2 0)//工作正常
(增量状态)|>应该等于(状态二|)//我想写这个。。。
(增量状态)|>应为instanceOfType/…或此
这可以在FsUnit中完成吗
我知道,但不希望为每种情况都编写匹配函数(在我的实际代码中,匹配函数远远不止两个)。它看起来不太优雅,但您可以从状态值中提取类型:
let instanceOfState (state: 'a) =
instanceOfType<'a>
let instanceOfState(状态:'a)=
instanceOfType如果您不介意使用反射,则来自的isUnionCase
函数可能很方便:
increment state
|> isUnionCase <@ StateTwo @>
|> should equal true
这样,您可以定义一次分类,然后多次使用它
increment state
|> categorize
|> should equal StateTwoCase
FSUnit似乎不(或者不能,我不确定)直接支持这个用例
我发现的下一个最好的方法是声明一个TestResult
类型,如下所示,并使用一个匹配项将结果简化为该类型
type TestResult =
| Pass
| Fail of obj
这是比赛
let testResult =
match result with
| OptionA(_) -> Pass
| other -> Fail(other)
现在您可以使用应等于来确保结果正确
testResult |> should equal Pass
此解决方案的好处是强类型,但更重要的是在失败案例中,您可以看到无效结果是什么如果已经支持针对特定联合案例的断言,尽管该断言仅限于Microsoft.FSharp.Core.Choice类型的值
让我们用一个多案例活动模式来利用它,它使用反射来检查联合案例名称
open System.Reflection
open Microsoft.FSharp.Reflection
let (|Pass|Fail|) name (x : obj) =
let t = x.GetType()
if FSharpType.IsUnion t &&
t.InvokeMember("Is" + name,
BindingFlags.GetProperty, null, x, null )
|> unbox then Pass
else Fail x
现在应该可以工作了:
increment state
|> (|Pass|Fail|) "StateTwo"
|> should be (choice 1)
实际上,有一种相当简单的方法可以从C#中执行此操作,但在F#中不起作用。这似乎不起作用-即使我使用StateOne 88
,测试也会通过,因此不检查值是否为StateTwo
。这不起作用,因为'a
类型将只是MyState
。如果instanceOfState
使用了有关参数state
的运行时类型信息,那么它就可以工作了,但这意味着它需要以稍微不同的方式工作。。。
let testResult =
match result with
| OptionA(_) -> Pass
| other -> Fail(other)
testResult |> should equal Pass
open System.Reflection
open Microsoft.FSharp.Reflection
let (|Pass|Fail|) name (x : obj) =
let t = x.GetType()
if FSharpType.IsUnion t &&
t.InvokeMember("Is" + name,
BindingFlags.GetProperty, null, x, null )
|> unbox then Pass
else Fail x
increment state
|> (|Pass|Fail|) "StateTwo"
|> should be (choice 1)