F# Object Expressions vs Mocking Libraries: Am I Missing Something?

Object expressions are a cool feature of F#. For those unfamiliar, they allow you to easily instantiate anonymous classes:

let mutable disposed = false

let anonomousType = 
    { new IDisposable with
          member this.Dispose() =
              disposed <- true }

Assert.IsTrue(disposed)

There are times when it’s useful to instantiate anonymous classes in this fashion (a topic for another post), but I’m not convinced that mocking is one of them. However, based on based on a couple of twitter conversations that I’ve had with notable F# community members Richard Minerich and Steffen Forkmann, my opinion may be in the minority. I understand their opinions in theory, but in practice, I find that object expressions are inferior to Mocking Libraries for generating mock objects.

I will go over a few advantages of mocking libraries below, but before I do that, I would like to define what I mean by “mock object” in this post. The term “mock” is a loaded one in the testing world, and it seems like everyone has their own opinion about what the words mock, dummy, stub, spy, fake, and test double actually mean. I’m far less dogmatic about this. For the rest of the post, consider a mock to be any object that takes the place of another for the purpose of testing.

Abstraction vs Verbosity

In his tweet, Steffen says that he believes object expressions are much clearer than mock libraries. On one hand, I understand his reasoning; mock libraries use more abstraction than object expressions, and abstraction can make code more difficult to understand. Ironically, I find this argument to be very similar to one that I often hear from people who favor for loops over the use of LINQ or higher order functions like that in the F# Seq module. They prefer the verboseness of a for loop to the abstraction of a library function.

I often use a simple example to explain the advantages of the F# Seq module over for/foreach loops. The goal is to find the sum of the squares of the even numbers less than or equal to ten.

IEnumerable<int> values = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

int sum = 0;

foreach (int value in values)
{
    if (IsEven(value))
    {
        sum += Square(value);
    }
}

Assert.AreEqual(220, sum);
let numbers = [0..10]

let sum =
    numbers
    |> List.filter IsEven
    |> List.map Square
    |> mySum

I don’t know any functional programmer who would argue that the for/foreach loop is clearer than the version using the List module. They understand and accept the abstraction of higher order functions, so the abstraction actually adds clarity to the code.

Now lets consider a typical testing scenario. Given a dummy interface, IFoo:

type IFoo =
    abstract foo: int -> int

The goal is to create a mock IFoo that validates that foo was called and also returns a dummy value for foo.

First is a F# solution with object expressions:

let mutable wasCalled = false
let mock =
    { new IFoo with
        member this.foo x =
            wasCalled <- true
            0 }

let result = aFunctionThatDependsOnIFoo(mock)

Assert.IsTrue(wasCalled)
Assert.AreEqual("the expected value", result)

Now here’s a C# implementation using MOQ:

var mock = new Mock<IFoo>();
mock.Setup(f => f.foo(It.IsAny<int>())).Returns(0);

var result = aFunctionThatDependsOnIFoo(mock.Object);

mock.Verify(f => f.foo(It.IsAny<int>()), Times.Once());

Assert.AreEqual("the expected value", result);

Like the List module in the first example, MOQ encapsulates the logic required to create mock objects into helper functions, and like the foreach loop, the object expression puts all of that wiring in the test. Code like the foreach loop and object expression is simple to read and write, but it’s code that a library can and should take care of. By factoring out the common bits into a helper library, your code becomes less error prone, less brittle, and easier to maintain. As with LINQ and the Seq/List module, mocking frameworks require that you accept and understand a small degree of abstraction, but it’s the abstraction that makes your code more clear.

Scalability

Object expressions are manageable for small interfaces, but they quickly become unwieldy if you want to mock an interface that contains multiple methods. For example, let’s say you want to mock a method on an interface with 4 methods using object expressions:

type IFoo2 =
    abstract foo1: int -> int
    abstract foo2: int -> int
    abstract foo3: int -> int
    abstract foo4: int -> int

let mock =
    { new IFoo2 with
        member this.foo1 x =
            0 
        member this.foo2 x =
            0 
        member this.foo3 x =
            0 
        member this.foo4 x =
            0 }

That’s a lot of work to just mock one method one time. IFoo2 doesn’t have any complicated method signatures, and you aren’t even validating that methods are called. With a mocking library, all of that work is accomplished in two lines of code.

var mock = new Mock<IFoo2>();
mock.Setup(f => f.foo1(It.IsAny<int>())).Returns(0);

Maintainability

Let’s say that you’re using the IFoo2 interface in a production codebase with a few hundred tests. Now the requirements change and you need to add a new method to IFoo2. With the object expression syntax, you have to go through and change every object expression to add a default implementation for that method. Even if you don’t have a separate mock object for every test, it’s still a lot of overhead for a relatively small change. With mocking library, you don’t have to change any of your code. All of your tests work the same way they did before, and you can focus on the task at hand instead of maintaining your tests.

Closing Thoughts

Object expressions are a little better than creating a new type every time you want to mock, but I think the above arguments apply in both cases. I don’t know many C# developers who prefer hand rolling new mock classes to mocking libraries, and I don’t understand what makes object expressions different. That being said, I know there are some great F# coders who have a different opinion, so I would love to hear the other side of the story via comments, twitter, a fierce blog-off, etc. : )

I should also point out that while I love MOQ for creating mock objects in C#, I wouldn’t recommend it for use from F#. It relies heavily on LINQ expressions which are difficult to create via F#, and even in the best case, it pollutes your code with a lot of quotations. I would gladly pay someone a shiny quarter if they would write an F# wrapper over MOQ or (even better) a mocking library specifically targeted for F#.

This entry was posted in F#, testing, Unit Testing. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

One Comment

  1. Posted November 18, 2012 at 7:50 pm | Permalink

    Fast forward 2 years and there’s now a mocking library specifically targeted for F# with a similar API to Moq called Foq:

    http://foq.codeplex.com/

    Phil

One Trackback

  1. By F# as a Unit Testing Language on November 21, 2012 at 10:25 pm

    [...] F# Object Expressions vs Mocking Libraries: Am I Missing Something? – Chris Marinos' Blog [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>