Mathias Brandewinder on .NET, F#, VSTO and Excel development, and quantitative analysis / machine learning.
by Mathias 26. January 2013 19:08

Phil Trelford recently released Foq, a small F# mocking library (with a very daring name). If most of your code is in F#, this is probably not a big deal for you, because the technique of mocking isn’t very useful in F# (at least in my experience). On the other hand, if your goal is to unit test some C# code in F#, then Foq comes in very handy.

So why would you want to write your unit tests in F# in the first place?

Let’s start with some plain old C# code, like this:

namespace CodeBase
{
    using System;

    public class Translator
    {
        public const string ErrorMessage = "Translation failure";

        private readonly ILogger logger;
        private readonly IService service;

        public Translator(ILogger logger, IService service)
        {
            this.logger = logger;
            this.service = service;
        }

        public string Translate(string input)
        {
            try
            {
                return this.service.Translate(input);
            }
            catch (Exception exception)
            {
                this.logger.Log(exception);
                return ErrorMessage;
            }
        }
    }

    public interface ILogger
    {
        void Log(Exception exception);
    }

    public interface IService
    {
        string Translate(string input);
    }
}
We have a class, Translator, which takes 2 dependencies, a logger and a service. The main purpose of the class is to Translate a string, by calling the service. If the call succeeds, we return the translation, otherwise we log the exception and return an arbitrary error message.

This piece of code is very simplistic, but illustrates well the need for Mocking. If I want to unit test that class, there are 3 things I need to verify:

  • when the translation service succeeds, I should receive whatever the service says is right,
  • when the translation service fails, I should receive the error message,
  • when the translation service fails, the exception should be logged.

In standard C#, I would typically resort to a Mocking framework like Moq or NSubstitute to test this. What the framework buys me is the ability to create cheaply a fake implementation for the interfaces, setup their behavior to whatever my scenario is (“stubbing”), and in the case of the logger, where I can’t observe through state whether the exception has been logged, verify that the proper call has been made (“mocking”).

This is how my test suite would look:

namespace MoqTests
{
    using System;
    using CodeBase;
    using Moq;
    using NUnit.Framework;

    [TestFixture]
    public class TestsTranslator
    {
        [Test]
        public void Translate_Should_Return_Successful_Service_Response()
        {
            var input = "Hello";
            var output = "Kitty";

            var service = new Mock<IService>();
            service.Setup(s => s.Translate(input)).Returns(output);

            var logger = new Mock<ILogger>();

            var translator = new Translator(logger.Object, service.Object);

            var result = translator.Translate(input);

            Assert.That(result, Is.EqualTo(output));
        }

        [Test]
        public void When_Service_Fails_Translate_Should_Return_ErrorMessage()
        {
            var service = new Mock<IService>();
            service.Setup(s => s.Translate(It.IsAny<string>())).Throws<Exception>();

            var logger = new Mock<ILogger>();

            var translator = new Translator(logger.Object, service.Object);

            var result = translator.Translate("Hello");

            Assert.That(result, Is.EqualTo(Translator.ErrorMessage));
        }

        [Test]
        public void When_Service_Fails_Exception_Should_Be_Logged()
        {
            var error = new Exception();
            var service = new Mock<IService>();
            service.Setup(s => s.Translate(It.IsAny<string>())).Throws(error);

            var logger = new Mock<ILogger>();

            var translator = new Translator(logger.Object, service.Object);

            translator.Translate("Hello");

            logger.Verify(l => l.Log(error));
        }
    }
}

More...

by Mathias 21. April 2012 05:34

I presented “For Those About to Mock”, an introduction to Mocking for C# developers, at the San Francisco chapter of Bay .NET last week, and promised I would make the material available.

Here it is: you can download the code “For Those About to Mock” here.

Thanks for everyone who made it, it was a great crowd with lots of good questions – I had a great time!

by Mathias 4. December 2011 15:47

I am in the middle of “Working Effectively with Legacy Code”, and found it every bit as great as it was said to be. In the book, Feathers introduces the concept of Seams and Enabling Points:

a Seam is a place where you can alter behavior in your program without editing it in that place

every seam has an enabling point, a place where you can make the decision to use one behavior or another.

The idea - as I understand it - is that an enabling point is a hook for testability, a place where you can replace the behavior of a piece of code with your own controlled behavior, and validate that the results are as expected.

The reason I am bringing this up is that I have been writing lots of F# lately, and it made me realize that a functional style provides lots of enabling points, and can be much easier to test than object-oriented code.

Here is a simplified, but representative, example of the problem I was looking at: I needed to pick a random item in a list. In C#, a method along these lines would do the job:

public T PickFrom(IList<T> list)
{
   var random = new Random();
   return list[random.Next(list.Count())];
}

However, this code is utterly untestable; it’s also probably a terrible idea to instantiate a new Random every time this is called, so we modify it this way:

public T PickFrom(IList<T> list, Random random)
{
   return list[random.Next(list.Count())];
}

This is much better: now we have a decent Enabling Point, because the list of arguments of the method contains everything that is used inside the method. However, this is still untestable, but for a different reason: by definition, Random.Next() will return different values every time PickFrom is called, and expecting a repeatable result from PickFrom is a bit of a desperate enterprise.

More...

by Mathias 10. October 2011 15:48

Huge thanks to everyone who came to my presentations at Silicon Valley Code Camp this year – and to the organizers. It’s amazing to me how the event has been growing up year after year, and yet retains its friendly atmosphere, and smooth organization.

For Those About to Mock

I uploaded the entire code sample, illustrating how to roll your own, and how to achieve the same result with Moq, Rhino and NSubstitute here. The slides are included as well. Note that it assumes you have installed NUnit on your machine. If this isn’t the case, some of the projects won’t build.

An excursion in F#

The code sample is uploaded here. I must say, I was very pleasantly surprised by the level of enthusiasm of the audience, especially so because it was very late in the program. Sorry again for the string of technical glitches, and thank you for being really awesome, this session was a memorable one for me, thanks to you all!

Notes:

1) one of the projects (FSharp.StockReader) will not build unless you have the F# PowerPack installed on your machine, because it uses the Async extensions which come with it. Either install it, or unload FSharp.StockReader and CSharp.ConsoleClient.

2) In Stocks.FSharp.Scripts, you will have to modify the first line of the code to point to the location of FSharpCharts.fsx on your local machine.

That’s it! I haven’t added material for the TDD session because all the code was written live, and the slide deck can be largely summarized with Red, Green, Refactor – if you want me to add that as well, let me know!

Download "For Those About to Mock"

Download "An Excursion in F#"

by Mathias 25. September 2011 05:31

headCodeCamp

It’s this time of the year again: on Saturday & Sunday October 8 + 9, Silicon Valley CodeCamp is taking place at Foothill College in Los Altos Hill. There are currently over 200 sessions listed, and 2000 people signed up already. I am expecting lots of fun - again.

I’ll be giving 3 talks this year:

  • Sat, 11:45 - Beginning TDD for C# Developers.
  • Sun, 1:15: For Those About to Mock.
  • Sun, 2:45: An excursion in F#

Hope to see you there, and also that I will have some energy left to attend some of the other talks!

More information about my talks here.

Comments

Comment RSS