我想对接受DU并返回另一个的函数进行一些单元测试:
type Commands =
| Schedule of string
| Abandon of string
type Events =
| Scheduled of string
| Abandonned of string
该功能如下:
let exec state = function
| Schedule (cmd) -> Choice1Of2( Scheduled("yes"))
| Abandon(cmd) -> Choice1Of2( Abandonned ("no"))
我的测试如下:
let result:Choice<Events,string> = exec "initial state" <| Schedule("myCommand");;
结果有以下类型Choice<Events,string>
,我本来希望得到一些快速功能,以便像这样使用它们:
assertEvent Scheduled (fun e -> Assert.Equal("should produce GameScheduled Event",gameScheduled, e)) result
但要做到这一点,我将拥有以下自制的断言功能:
let assertEvent<'TEvent> f g result =
match result with
| Choice1Of2(e) ->
match e with
| f(evt) -> g(evt)
| _ -> Assert.None("event not recognised",Some(e))
| Choice2Of2(reason) -> Assert.None("reason",Some(reason))
我期待函数f允许动态模式匹配,但事实并非如此。相反,我有以下错误:
The pattern disciminator 'f' is not defined
我在某处做错了吗?我的fsharp技能不是那么高......
答案 0 :(得分:4)
像f
这样的普通函数不能用作模式鉴别器,但可以传递Active Patterns作为参数:
let assertEvent<'TEvent> (|F|_|) g result =
match result with
| Choice1Of2(e) ->
match e with
| F(evt) -> g(evt)
| _ -> Assert.None("event not recognised",Some(e))
| Choice2Of2(reason) -> Assert.None("reason",Some(reason))
但是,这确实要求您也将活动模式作为参数传递,这有点麻烦:
assertEvent
(function Scheduled(x) -> Some x | _ -> None)
(fun e -> Assert.Equal("should produce GameScheduled Event",gameScheduled, e))
result
但这不是我解决问题的方法。我更喜欢写一个布尔表达式,试图拉出并比较我想要验证的值。
对于初学者,您可以创建一个小的通用辅助函数来从Choice<'a, 'b>
中提取其中一个选项:
let toOption1 = function Choice1Of2 x -> Some x | _ -> None
此函数的类型为Choice<'a,'b> -> 'a option
。 (我将把它作为练习来定义一个等效的toOption2
函数。)
现在你可以定义一个布尔表达式来拉出数据,如果它存在,并将它与预期值进行比较:
result
|> toOption1
|> Option.map (function Scheduled x -> x | _ -> "")
|> Option.exists ((=) expected)
这是一个布尔表达式,因此您可以使用Unquote将其转换为断言。这类似于this approach that I've previously described。