A colleague of mine needed to test whether some F# functions are called or not a given number of times.
In Moq, you can usually do that if you have a class with virtual members or an interface (unless if this has changed, but it doesn't seem to be the case), but afaik you can hardly mock static methods with Moq for example, which in most cases is how F# functions are compiled to, at least from an IL standpoint. Or, would require to use another library to do so like AutoFake or Pose and I'm not sure the F# support is actually properly implemented.
We ended up creating a CallCounter
type, which would hold the function to invoke and a variable counting the number of times this function has been invoked (a bit similar to this answer but with an actual type).
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 @>
I was wondering if there was something out of the box in Moq to achieve the same sort of thing?
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)