F# 3 has LINQ expression support built-in just like C# and VB.Net. Prior to this basic LINQ expression interop could be achieved with the F# PowerPack and F# Code Quotations.
F# 3 LINQ support opens up APIs that use LINQ expressions like Moq, a popular .Net mocking library. With some minor workarounds Moq is relatively easy to call from F#.
C# Moq example:
var mock = new Mock<IFoo>();
mock.Setup(foo => foo.DoSomething("ping")).Returns(true);
F# requires a type annotation:
F# requires the return value to be explicitly ignored:
F# Moq example with required type annotation and return value piped to ignore:
let mock = Mock<IFoo>()
mock.Setup<bool>(fun foo -> foo.DoSomething("ping")).Returns(true) |> ignore
The type annotation is required as the Setup method provides multiple overloads with differing generic parameters. Another way to workaround this is to write specific extension methods for overloads:
type Moq.Mock<'T> when 'T : not struct with
/// Specifies a setup on the mocked type for a call to a function
member mock.SetupFunc<'TResult>(expression:Expression<Func<'T,'TResult>>) =
mock.Setup<'TResult>(expression)
/// Specifies a setup on the mocked type for a call to a void method
member mock.SetupAction(expression:Expression<Action<'T>>) =
mock.Setup(expression)
/// Specifies a setup on the mocked type for a call to a property setter
member mock.SetupSetAction<'TProperty>(setupExpression:Action<'T>)
: Moq.Language.Flow.ISetupSetter<'T,'TProperty> =
mock.SetupSet<'TProperty>(setupExpression)
The ignore statement is required as F# requires return values to be handled explicitly. Moq’s fluent inteface provides some methods where the return value is ignorable.
The issues using Moq’s API from F# 3 can be fairly easily worked around. That said for an API designed specifically for F# consider using Foq which has similar functionality to Moq and supports both Code Quotations and LINQ expressions. You may also find F#’s built-in Object Expressions sufficient for many tasks.