Моему коллеге нужно было проверить, вызываются ли некоторые функции F # заданное количество раз или нет.
В Moq это обычно можно сделать, если у вас есть класс с виртуальными членами или интерфейс ( если это не изменилось, но, похоже, это не так), но afaik вы вряд ли сможете имитировать методы stati c с помощью Moq , например, который в большинстве случаев соответствует F # функции компилируются в , по крайней мере, с точки зрения IL. Или для этого потребуется использовать другую библиотеку, например AutoFake или Pose , и я не уверен, что поддержка F # действительно реализована должным образом.
Мы закончили создание типа CallCounter
, который будет содержать вызываемую функцию и переменную, подсчитывающую, сколько раз эта функция была вызвана (немного похоже на этот ответ , но с фактическим типом).
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 для достижения того же самого?
Я имею в виду без необходимости полагаться на создание интерфейса заполнителя с имп. использование объектных выражений просто ради сохранения вызываемой функции, чтобы сделать ее совместимой с 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)