3

In C# I used to write

var provider = A.Fake<ITimeProvider>();
A.CallTo(() => provider.Fetch()).ReturnsLazily(call => data[0]);
container.Register(() => provider);

to capture calls to Fetch().

When I've tried the same with F#

let provider = A.Fake<ITimeProvider>()
A.CallTo(fun () -> provider.Fetch()).ReturnsLazily(fun call -> data.[0]) |> ignore
container.Register(fun () -> provider)

the test fails with

Test Error : ....Test
System.ArgumentException : The specified object is not recognized as a fake object.
at Microsoft.FSharp.Control.AsyncBuilderImpl.commit[a](Result`1 res)
at Microsoft.FSharp.Control.CancellationTokenOps.RunSynchronously[a](CancellationToken token, FSharpAsync`1 computation, FSharpOption`1 timeout)
at Microsoft.FSharp.Control.FSharpAsync.RunSynchronously[T](FSharpAsync`1 computation, FSharpOption`1 timeout, FSharpOption`1 cancellationToken)
...

It looks like for F# it should be defined a bit differently. Have you some idea how?

Alex Netkachov
  • 13,172
  • 6
  • 53
  • 85
  • I'm not an F# person, but were I trying to write F#, and I got this. I'd say to myself, "what type does `fun () => provider.Fetch`" resolve to? In order for FakeItEasy to work with it, it should be the equivalent of an `Expression>`. – Blair Conrad Aug 17 '15 at 17:51
  • I'm not a FakeItEasy person, but if FakeItEasy depends on parsing or reflecting over lambda expressions, then you're out of luck. F# functions are not lambda expressions in the sense that you can manipulate them using C# expression API, despite a similar syntax. – scrwtp Aug 17 '15 at 20:33

1 Answers1

6

FakeItEasy uses LINQ expressions, which are supported in F# 3, however there appears to be an incompatibility when using the static API. Based on the error message "object is not recognized as a fake object" I suspect that in this case the resolution of the object is C#/VB.Net specific.

FakeItEasy's instance member based setup does however appear to work:

let fake = Fake<ITimeProvider>()
fake.CallsTo(fun x -> x.Fetch()).ReturnsLazily(fun () -> data.[0]) |> ignore
let provider = fake.FakedObject

Another option is to use F# and Moq (here I'm using the Moq.FSharp.Extensions):

let mock = Mock<ITimeProvider>()
mock.SetupFunc(fun x -> x.Fetch()).Returns(data.[0]).End
let provider = mock.Object

Or alternatively Foq, which was designed specifically for F#:

let provider = 
    Mock<ITimerProvider>.Method(fun x -> <@ x.Fetch @>).Returns(data.[0])
Phillip Trelford
  • 6,513
  • 25
  • 40