Phillip Trelford's Array

POKE 36879,255

Foq It Easy

Foq is a .Net mocking library with first class support for F# and a cool sounding name. After 9 public releases, Foq is now mature and stable at version 0.9. What started as a 6 to 8 week project ended up more like a half-year project. At this point, I’d like to say a big thank you for the great feedback from the community, and specifically acknowledge the help and support of Mathias Brandewinder, Vasily Kirichenko, Niklas Bergius and Neil Danson. Yesterday the first Foq question appeared on Stack Overflow, thanks to Michael Newton.

F# makes unit testing easy with static method support in xUnit and NUnit, white space in method names and object expressions for mocking simple interfaces:

let [<Test>] ``at 15:00 the sun image should be expected`` () =
    let time = { new ITime with member mock.GetHour() = 15 }
    let calculator = ImageCalculator(time)
    let image = calculator.GetImageForTimeOfDay()
    Assert.AreEqual("sun.jpg",  image)

Foq provides a fluent interface for scaling up to larger interfaces like IList(T), where there are many members, but you may only be interested in specifying return values for a few of them:

let [<Test>] ``setup a method to always return true`` () =
    // Arrange
    let instance =
        Mock<IList>()
            .Setup(fun xs -> <@ xs.Contains(any()) @>).Returns(true)
            .Create()
    // Assert
    Assert.IsTrue(instance.Contains("Anything"))

Foq’s API is quite similar to Moq’s or FakeItEasy’s. Not only does it support LINQ expressions there’s F# Code Quotations too. I tend to think of Code Quotations like classic ASP code blocks <% .. %> for quoting code but with @’s <@ … @>. Code Quotations add a little syntactic noise but come with more expression types than LINQ expressions, so far example you can specify events as you would properties. If however you prefer your lambdas with less symbols then just open the Foq.Linq namespace instead.

Foq also provides some handy shortcuts like the Method method:

let [<Test>] ``setup a method to always return true`` () =
    // Arrange
    let instance =
        Mock<IList>.Method(fun xs -> <@ xs.Contains @>).Returns(true)
    // Assert
    Assert.IsTrue(instance.Contains("Anything"))

Note that even the arguments are omitted from the invocation of Contains for ease.

Where the Method method lets you set up a single method, the With method lets you setup multiple methods with a single method:

Mock<IList<char>>.With(fun xs ->
    <@ xs.Count --> 2 
       xs.Item(0) --> '0'
       xs.Item(1) --> '1'
       xs.Contains(any()) --> true
       xs.RemoveAt(2) ==> System.ArgumentOutOfRangeException()
    @>
)

Here a custom operator –-> is employed to signify returning a value from a member, and the ==> operator raising an exception. For setting up many members, letting go of the heavy fluent interface helps let the actual intent shine through.

Sometimes you just want an instance of an interface mocked which just follows the defaults, and like Moq you can easily specify Mock<T>.Of:

let [<Test>] ``order sends mail if unfilled`` () =
    // setup data
    let order = Order("TALISKER", 51)
    let mailer = Mock.Of<MailService>()
    order.SetMailer(mailer)
    // exercise
    order.Fill(Mock.Of<Warehouse>())
    // verify
    verify <@ mailer.Send(any()) @> once

The mock function lets F# type inference worry about the types for you:

let [<Test>] ``order sends mail if unfilled`` () =
    // setup data
    let order = Order("TALISKER", 51)
    let mailer = mock()
    order.SetMailer(mailer)
    // exercise
    order.Fill(mock())
    // verify
    verify <@ mailer.Send(any()) @> once

Foq support verification of calls as seen above, or you can specify expectations against members and even specific sequence of calls, as you would with the With method:

let xs = Mock<IList<int>>.ExpectSequence(fun xs ->
    <@
        xs.Clear()
        xs.[any()] --> any()
        xs.[any()] <- any()
        xs.Count --> any()
        xs.Contains(any()) --> any()
    @>)

Want to see some more examples, you got it:

All you need to play with Foq is to open an F# project in Visual Studio, Xamarin Studio or Tsunami and pull the Foq library from Nuget or simply reference Foq.fs in your project. Looking forward to more releases and more feedback :)

Pingbacks and trackbacks (1)+

Comments are closed