Phillip Trelford's Array

POKE 36879,255

Moq with F# 3

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:

TypeAnnotation

F# requires the return value to be explicitly ignored:

UseIgnore

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.

Pingbacks and trackbacks (1)+

Comments are closed