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 5. April 2010 11:59

A few weeks back, Michael asked an interesting question in a comment: how do you go about unit testing a VSTO project? One of the reasons I prefer working with VSTO over VBA, is that it makes it possible to write automated tests. What I realized with this question, though, is that I unit test heavily the .Net functionality of my add-ins, but not much (if at all) the interaction with Excel.

Note: I am aware of the existence of a VBA unit testing solution, xlUnit; I found the project conceptually pretty cool, but from a practical standpoint, it doesn’t seem nearly as convenient as NUnit or the other established frameworks, which isn’t much of a surprise, given the maturity of unit testing in the .Net world.

The reason for this is double. First, most of my VSTO projects focus on generating heavy computation outside of Excel, and writing results to Excel; as a result, the meat of the logic has little to do with Excel, and there isn’t all that much to test there.

Then, testing against VSTO is a bit of a pain. By definition, a VSTO project comes attached with a giant external dependency to Excel, which we have limited control over, and which is also rather unpleasant to deal with from .Net. To illustrate one aspect of the issue, let’s consider this code snippet:

[TestFixture]
public class TestsThisAddIn
{
   [Test]
   public void WeCannotInstantiateTheAddInProperly()
   {
      var addIn = new ThisAddIn();
      var excel = addIn.Application;
      Assert.IsNotNull(excel);
   }
}

This test will fail: if we instantiate the add-in directly, it does not automatically hook up to Excel. The VSTO add-in is started up by Excel itself, and we cannot replicate that simply in our test code, and access the Excel object to verify that things behave as expected.

So how could we approach the problem? Unit testing our code means that we want to validate that pieces under our control (classes we wrote) work properly; the challenge is that some of them interact with Excel. We are not concerned with testing the system in its entirety (add-in code + Excel) here, which is an important issue, but not a unit-testing one.

The words “unit test” and “external dependency” together suggest one technique – Mocking. In a nutshell, Mocking consists of replacing the external dependency with a fake, an object which behaves the same way as the “real thing”, but is easier to work with.

There are three ways our classes can interact with Excel that I can think of:

  • react to Excel events
  • read/query from Excel
  • write/command to Excel

More...

by Mathias 6. October 2009 06:09

Silicon Valley Code Camp version 4.0 took place this week-end, and was a big success, judging by the numbers and the happy faces. Congratulations to Peter Kellner and the team for a tremendous organization!

Personally, I wanted to give a big thank-you to the people who attended my session on Test-Driven Development – and for bearing with my voice, which was pretty shaky. I got sick this week and wasn’t sure until Saturday evening if I could do it, because on Thursday my voice was totally gone. I think I had more herbal tea with honey this week than in my entire life, but you guys made it all worth it: I had a great time giving my presentation, and you guys rocked!

As I said during the session, the theory behind TDD is pretty succinct, so there isn’t much in the slides themselves worth posting. Instead, I thought I would list a few pointers:

NUnit: you can find it here. I recommend checking out the Quick Start page, which covers most of what you need to start writing unit tests. I have written a post on data-driven tests here.

While we are talking about tools, I haven’t presented it during the session, but I really like TestDriven.Net. There is a free community version for your personal use. It’s a Visual Studio add-on which allows you to run and debug your tests from Visual Studio.

Even though it’s a Java book, and this session was for .NET developers, I really recommend Kent Beck’s book Test-Driven Development by Example. It’s very easy to read, and will get you started on the right foot. It’s also very well written – one of my favorite books!

The other book I recommend is the Art of Unit Testing, by Roy Osherove. I just finished it, and I wish I had it with me a few years ago, when I began writing tests seriously :) The book is technically about unit testing and not TDD, and it is a .NET book. I highly recommend it, it is chock-full of good advice, and covers way more than just testing.

That’s it! If you are interested in either the slides or code, let me know, and I’ll gladly post them, too. In the meanwhile, thanks again for coming, and… happy testing!

by Mathias 18. September 2009 06:12

ghostmantisI found a bug in my code the other day. It happens to everybody - apparently I am not the only one to write bugs – but the bug itself surprised me. In my experience, once you know a piece of code is buggy, it’s usually not too difficult to figure out what the origin of the problem might be (fixing it might). This bug surprised me, because I knew exactly the 10 lines of code where it was taking place, and yet I had no idea what was going on – I just couldn’t see the bug, even though it was floating in plain sight (hint: the pun is intended).

Here is the context. The code reads a double and converts it into a year and a quarter, based on the following convention: the input is of the form yyyy.q, for instance, 2010.2 represents the second quarter of 2010. Anything after the 2nd decimal is ignored, 2010.0 is “rounded up” to 1st quarter, and 2010.5 and above rounded down to 4th quarter.

Here is my original code:

public class DateConverter
{
    public static int ExtractYear(double dateAsDouble)
    {
        int year = (int)dateAsDouble;
        return year;
    }

    public static int ExtractQuarter(double dateAsDouble)
    {
        int year = ExtractYear(dateAsDouble);
        int quarter = (int)(10 * (Math.Round(dateAsDouble, 1) - (double)year));
        if (quarter < 1)
        {
            quarter = 1;
        }
        if (quarter > 4)
        {
            quarter = 4;
        }
        return quarter;
    }
}

Can you spot the bug?

More...

by Mathias 24. July 2009 15:54

I really like the addition of [TestCase] in NUnit 2.5. A significant part of the code I write is math or finance oriented, and I find Data-Driven tests more convenient that “classic” unit tests to validate numeric procedures.

However, I got a bit frustrated today, because of the lack of tolerance mechanism in data-driven tests. Tolerance allows you to specify a margin of error (delta) on your test, and is supported in classic asserts:

[Test]
public void ClassicToleranceAssert()
{
    double numerator = 10d;
    double denominator = 3d;
    Assert.AreEqual(3.33d, numerator / denominator, 0.01);
    Assert.That(3.33d, Is.EqualTo(numerator / denominator).Within(0.01));
}

You can specify how close the result should be from the expected test result, here +/- 0.01.

I came into some rounding problems with data driven tests today, and hoped I would be able to resolve them with the same mechanism. Here is roughly the situation:

[TestCase(10d, 2d, Result = 5d)]
[TestCase(10d, 3d, Result = 3.33d)]
public double Divide(double numerator, double denominator)
{
    return numerator / denominator;
}

Not surprisingly, the second test case fails – and when I looked for a similar tolerance mechanism, I found zilch.

The best solution I got was to do something like this:

[TestCase(10d, 2d, Result = 5d)]
[TestCase(10d, 3d, Result = 3.33d)]
public double Divide(double numerator, double denominator)
{
    return Math.Round(numerator / denominator, 2);
}

Of course, this works – but this is clumsy. I was really hoping that TestCase would support the same functionality as Assert, with a built-in delta tolerance. It seems particularly relevant: rounding error issues are typical in numerical procedures, a field where data-driven tests are especially adapted.

Maybe the feature exists, but is undocumented. If you know how to do this, sharing your wisdom will earn you a large serving of gratitude, and if it the feature doesn’t exist yet… maybe in NUnit 2.5.1?

Comments

Comment RSS