Phil Trelford's Array
POKE 36879, 255

Foq 1.6

March 21, 2014 06:31 by phil

Foq is a mature open source .Net mocking library written in F#. It’s raison d'être is to enable F# as a unit testing language, for F#, C# or VB.Net code bases.

Foq is part a rich set of testing tools available to F# developers. Use Foq when unit testing in combination with staple .Net testing frameworks like NUnit and xUnit through to F# specific fluent assertion libraries like FsUnit and Unquote. Combine Foq with AutoFixture to simplify test setup even further.


The name Foq is derived from Moq, with Foq providing a familiar fluent interface:

// Moq from C#
var mock = new Mock<ILoveThisFramework>();
mock.Setup(framework => framework.DownloadExists("2.0.0.0"))
   .Returns(true);
ILoveThisFramework lovable = mock.Object;

// Foq from F#
let lovable = 
   Mock<ILoveThisFramework>()
      .Setup(fun framework -> <@ framework.DownloadExists("2.0.0.0") @>)
      .Returns(true)
      .Create()

The main difference in the setups above is that Moq uses mutation where as Foq is thread safe, favouring method chaining to build an immutable representation of the type.

Foq takes advantage of F#’s code quotations and type inference for shorter setups:

// Mock succinctly with Foq
let lovable =
   Mock.With(fun (framework:ILoveThisFramework) ->
   <@ framework.DownloadExists("2.0.0.0") --> true @>)

Getting Started

Get the latest version of Foq from Nuget or simply include Foq.fs in your test project. An F# script packed with examples is included when you install Foq via Nuget.

Then take a peek at some of the many Foq testing examples on CodePlex:

    New features

Back in April 2013, Foq’s API stabilized at version 0.9, since then new features and bug fixes have been requested via CodePlex, StackOverflow and Twitter.

Many of the requests have come from people testing C# codebases from F# and requiring extensive support for:

Testing C# Code

Foq can be used to mock both interfaces and abstract classes. For abstract classes arguments can be passed to the base constructor when the mock is created:

let mock = Mock<AbstractBaseClassWithConstructorArgs>().Create(7, "seven")
Assert.AreEqual("seven", mock.Name)

In F# multiple return values are easily specified using tuples, in C# out parameters are required. To setup C# methods with out parameters using Foq, simply specify the out arguments as tuples as you would normally from F#:

// Calling a method with out arguments from F#
let (success, value) = dict.TryGetValue("Fred")
// Setting up a method with out arguments using Foq
Mock<IDictionary<string,int>>()
   .SetupByName("TryGetValue").Returns((true, 1))
   .Create()

Testing Events

In F# events are first class, meaning they can be created like objects and passed to functions. To setup an event on an interface:

// Arrange
let event = Event<_,_>() 
let instance = 
      Mock<INotifyPropertyChanged>() 
         .SetupEvent(fun x -> <@ x.PropertyChanged @>).Publishes(event.Publish) 
         .Create() 
// Act 
event.Trigger(instance, PropertyChangedEventArgs("Name"))

Non-standard events can be setup using the SetupEventByName method.

Testing F# Code

Foq provides helpers for quickly mocking a single member be it a property:

Mock<MyAbstractBaseClass>.Property(fun x -> <@ x.MyProperty @>).Returns(1)

or a method (note that arguments do not need to be specified):

Mock<GreetingTime>
    .Method(fun gt -> <@ gt.GetGreeting @>)
    .Returns("Good Night")

Foq can now mock F# specific members with curried arguments e.g.

Mock<ICurry>()
    .Setup(fun curry -> <@ curry.Fun (any()) (any()) @>)
    .Returns(true)
    .Create()

Finally Mock.With now supports return values via functions:

Mock<IFoo>.With(fun foo -> 
    <@ 
        foo.Bar(1) --> 1
        foo.Bar(any()) ---> fun () -> 2
    @>)

What next?

Try F# as a testing language for your .Net code bases and use Foq to mock F# and C# types with ease. Then try web testing with canopy, automated acceptance testing using NaturalSpec, TickSpec or SpecFlow or random testing via FsCheck.


Tags:
Categories: F# | C# | .Net
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Comments

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading