【发布时间】:2020-10-10 07:48:10
【问题描述】:
我的一位同事需要测试某些 F# 函数是否被调用了给定的次数。
在 Moq 中,如果您有一个带有虚拟成员或接口的类,您通常可以这样做(除非这已更改,但似乎并非如此),但例如 afaik you can hardly mock static methods with Moq,其中 @ 987654322@,至少从 IL 的角度来看。或者,需要使用另一个库来执行此操作,例如 AutoFake 或 Pose,我不确定 F# 支持是否真正得到正确实现。
我们最终创建了一个CallCounter 类型,它将保存要调用的函数和一个计算该函数被调用次数的变量(有点类似于this answer,但有一个实际类型)。
module Tests
open Foq
open Xunit
open Swensen.Unquote
type CallCounter<'Input, 'Output>(f: 'Input -> 'Output) =
let mutable count = 0
member this.Count = count
member this.Invoke(input) =
count <- count + 1
f input
type CallOutputs<'Input, 'Output>(f: 'Input -> 'Output) =
let outputs = ResizeArray()
member this.Outputs =
List.ofSeq outputs
member this.Invoke(input) =
let output = f input
outputs.Add(output)
output
let callFunDepTwice (funDep: unit -> int32) =
sprintf "%A|%A" (funDep()) (funDep())
[<Fact>]
let ``callFunDepTwice should work1``() =
let funDep = fun() -> 42
let funDepCounter = CallCounter(funDep)
let actual = callFunDepTwice funDepCounter.Invoke
test <@ actual = sprintf "%A|%A" 42 42 @>
test <@ funDepCounter.Count = 2 @>
我想知道在 Moq 中是否有开箱即用的东西来实现同样的目标?
type ISurrogate<'Input, 'Output> =
abstract member Invoke: 'Input -> 'Output
[<Fact>]
let ``callFunDepTwice should work2``() =
let mockConf = Mock<ISurrogate<unit, int32>>().Setup(fun x -> <@ x.Invoke() @>).Returns(42)
let mock = mockConf.Create()
let actual = callFunDepTwice mock.Invoke
test <@ actual = sprintf "%A|%A" 42 42 @>
Mock.Verify(<@ mock.Invoke() @>, Times.exactly 2)
【问题讨论】: