How to: (Kill a) Mocking(bird)

An entry about tdd | nnug Publication date 1. March 2008 23:15

No, this isn't going to be a synopsis of the 1960 award-winning novel by Harper Lee, but rather an introduction to how writing unit tests more efficiently using a trick known as mocking. On Thursday I held a talk about just this topic at the Norwegian .NET User Group meeting (which was awesome by the way, thanks to everyone who attended!); instead of just upping the slides (which are in Norwegian anyway) and source code I thought I'd do you one better and rewrite it as a blog post.

Testing is Not as Easy as it Looks...

Thomas Eyde gave an excellent introduction to Test-driven Development before we served the pizza, explaining how test-first is more of a design philosophy than merely a testing strategy. To be able to write efficient unit tests, we have to allow for designing our code accordingly. We want each of our tests to be narrowly focused, testing one thing at a time - they're called unit tests, after all. And while this may look easy enough when just considering small demo applications, oftentimes we're working on much larger, more complicated projects. What do we do when there's no easy way to separate the units? What do we do when objects need other objects to function, or even external resources like configuration files, databases or webservices hosted on the other side of the world?

Isolation is The Key

What we need, is the ability to isolate each unit from any dependencies it has on other units. To do this, we need to loosen the coupling between classes. There's a livid debate going on in the blogosphere about how this leads to a new design philosophy dubbed design for testability as opposed to designing APIs as deliverables, whether testability is in itself the ultimate goal, and if its sacrifice of cohesion for loose coupling is a cost we should be willing to bear. I've touched on the subject before, and in the context of this post it is, while not irrelevant, at least dismissible. We want to test our code, and we want to do it as efficiently and non-intrusive as possible while sacrificing as little time and energy as possible so we can make that looming deadline.

Houston, We Have a Problem

I didn't want to spend a lot of time debating the merits of this and that during my talk, and quickly jumped ship on poor old PowerPoint in favor of showing some real code. First, I presented a problem scenario in which I had some code and a test for it that failed miserably:

[TestMethod]
public void CalculateTotalCostForSingleOrderLine()
{
    IOrder order = new Order();
 
    order.OrderLines.Add(new OrderLine("Item #1", 1, 25.50, 0.5));
 
    const double expected = 25.50;
    double actual = order.CalculateTotalCost();
 
    Assert.AreEqual(expected, actual);
}

 

The test itself looks innocent enough. We want to verify that the CalculateTotalCost method is indeed calculating the cost correctly for a single order line with a price of 25.50. However, running the test throws a SqlException - our test is trying to hit a database! Ouch, that can't be good. Let's look at the CalculateTotalCost method to see if we can find the culpit:

public static double CalculateTotalCost(this IOrder order)
{
    double cost = 0;
 
    foreach(IOrderLine line in order.OrderLines)
    {
        cost += line.Cost*line.Amount;
    }
 
    foreach (IShippingCostRule rule in Rules.Find<IShippingCostRule>())
    {
        cost += rule.CalculateShippingCost(order);
    }
 
    return cost;
}

 

See that second foreach loop there? That's where the first warning light should go on - this method clearly has a tightly coupled dependency on the Rules class. The whole idea of unit testing is testing each unit in separation - our test for the CalculateTotalCost method should really not be dependent on the success on some other, unrelated component like the Rules class; the Rules class should be verified by a separate set of tests. And in this particular case, the dependency on Rules is in fact denying us from testing the CalculateTotalCost method at all, because it tries to read a configuration file and connect to a database to download the required ruleset - neither of which exists in the context of our test harness. Here's the code for it:

public static class Rules
{
    private static readonly List<object> _rules = new List<object>();
 
    static Rules()
    {
        // loading rules from a database 
        string cString = ConfigurationManager.ConnectionStrings[0].ConnectionString;
 
        using(IDbConnection connection = new SqlConnection(cString))
        {
            using(IDbCommand command = new SqlCommand("SELECT * FROM Rules"))
            {
                connection.Open();
 
                using(IDataReader reader = command.ExecuteReader())
                {
                    while(reader.Read())
                    {
                        string ruleTypeName = reader.GetString(0);
                        Type ruleType = Type.GetType(ruleTypeName);
 
                        object rule = Activator.CreateInstance(ruleType);
                        _rules.Add(rule);
                    }
                }
            }
        }
    }
 
    public static IEnumerable<T> Find<T>()
    {
        foreach(object rule in _rules)
        {
            if(rule is T)
            {
                yield return (T)rule;
            }
        }
    }
}

 

How are we supposed to get around this? Setting up a test database is not an option!

Designing for Testability...

To pass the test in the above scenario, we'd have to do a fair amount of refactoring. More precicely, we need to make the dependency on the Rules class pluggable. This will enable us to inject a mock implementation that fakes loading the rules into the code during our test, eliminating the dependency on the configuration file and database. After this refactoring, our code may look something like this:

public interface IRules
{
    IEnumerable<T> Find<T>();
}
 
public static class Services
{
    public static IRules _instance;
 
    public static IRules Rules
    {
        get
        {
            if (null == _instance)
            {
                _instance = new Rules(); //default
            }
 
            return _instance;
        }
        set { _instance = value; }
    }
 
}
 
public class Rules : IRules
{
    private readonly List<object> _rules = new List<object>();
 
    public Rules()
    {
        // loading rules from a database
 
        string cString = ConfigurationManager.ConnectionStrings[0].ConnectionString;
 
        using (IDbConnection connection = new SqlConnection(cString))
        {
            using (IDbCommand command = new SqlCommand("SELECT * FROM Rules"))
            {
                connection.Open();
 
                using (IDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        string ruleTypeName = reader.GetString(0);
                        Type ruleType = Type.GetType(ruleTypeName);
 
                        object rule = Activator.CreateInstance(ruleType);
                        _rules.Add(rule);
                    }
                }
            }
        }
    }
 
    public IEnumerable<T> Find<T>()
    {
        foreach (object rule in _rules)
        {
            if (rule is T)
            {
                yield return (T)rule;
            }
        }
    }
}

 

and then we need to change our CalculateTotalCost method to reflect these changes:

public static class OrderExtentions
{
    public static double CalculateTotalCost(this IOrder order)
    {
        double cost = 0;
 
        foreach(IOrderLine line in order.OrderLines)
        {
            cost += line.Cost*line.Amount;
        }
 
        foreach (IShippingCostRule rule in Services.Rules.Find<IShippingCostRule>())
        {
            cost += rule.CalculateShippingCost(order);
        }
 
        return cost;
    }
}

 

Notice how the method now asks the static Services class for the currently configured implementation of the IRules interface, and calls the find method on it? This will enable us to rewrite our test so that it can inject a mock implementation of IRules for usage during the test:

[TestMethod]
public void CalculateTotalCostForSingleOrderLine()
{
    Services.Rules = new MockRules(); // inject a mock implementation of IRules
 
    IOrder order = new Order();
 
    const double expected = 25.50;
 
    order.OrderLines.Add(new OrderLine("Item #1", 1, expected, 0.5));
    double actual = order.CalculateTotalCost();
 
    Assert.AreEqual(expected, actual);
}
 
public class MockRules : IRules
{
    public IEnumerable<T> Find<T>()
    {
        yield break;
    }
}

 

There we go, we've successfully isolated the CalculateTotalCost method, allowing us to test it as a stand-alone unit, eliminating its dependencies. However, we've introduced a degree of complication to our code that wasn't there before - the Services class - which exists solely for the purpose of making our code testable.

...Or Just Test It

What we did above, there are several frameworks that can help with, diminishing the amount of code we have to write. One such framework, and by far the most powerful one I've come across, is TypeMock Isolator. Where TypeMock really stands apart from other mocking framework, is its ability to not only mock interfaces and abstract classes, but just about anything you throw at it. In fact, in our above scenario it allows us to roll back our code to what it looked like before we started refactoring, and instead go in and surgically remove the dependency from our test without changing a single line of the code being tested. Here's the revised test method:

[TestMethod]
public void CalculateTotalCostForSingleOrderLine()
{
    MockManager.Init();
    Mock rulesMock = MockManager.Mock(typeof(Rules));
    rulesMock.ExpectAndReturn("Find", new IShippingCostRule[0]);
 
    IOrder order = new Order();
    order.OrderLines.Add(new OrderLine("Item #1", 1, 25.50, 0.5));
 
    double expected = 25.50;
    double actual = order.CalculateTotalCost();
 
    Assert.AreEqual(expected, actual);
 
    MockManager.Verify();
}

 

Essentially, TypeMock has the ability to hook into the CLR (using the Profiling API) and ambushing any type being created and dynamically mock it. In the above test, we've taken advantage of this and told TypeMock to hijack the instantiation of the Rules class. I say instantiation; even though it is a static class it does have a static constructor, and TypeMock is quite happy to mock it for us. We then tell TypeMock that the next time anyone tries to call the Find method on this (now mocked) Rules class, it should just return an empty array of IShippingCostRule instead of actually executing the real method. And there you go - with just a few lines of codes we've effectively stripped away the dependency on the real Rules class, with the exact same result we got from doing all that refactoring before. Awesome? I'd say so!

I did one last example in my demonstration, as I had a bit of extra time at the end. Imagine we wanted to write another test which should verify that the CalculateTotalCost method performed the correct calculation when also considering shipping rules. Now, we would want the Rules.Find method to actually return a rule and have it evaluated. However, we still don't want our test to depend on the real functionality of the Find method - or on any real implementation of the IShippingCostRule interface for that matter. Again we would turn to mocking, this time mocking the Find method into returning a mocked IShippingCostRule implementation. With TypeMock, this is less than even a walk in the park - we still don't have to leave our test method:

[TestMethod]
public void CalculateTotalCostForSingleOrderAndSingleShippingRule()
{
    MockManager.Init();
 
    Mock rulesMock = MockManager.Mock(typeof(Rules));
    Mock<IShippingCostRule> shippingCostMock = MockManager.MockObject<IShippingCostRule>();
    rulesMock.ExpectAndReturn("Find", new IShippingCostRule[] { shippingCostMock.MockedInstance });
    shippingCostMock.ExpectAndReturn("CalculateShippingCost", 150.0);
 
    IOrder order = new Order();
    order.OrderLines.Add(new OrderLine("Item #1", 1, 25.50, 0.5));
 
    double expected = 25.50 + 150.0;
    double actual = order.CalculateTotalCost();
 
    Assert.AreEqual(expected, actual);
 
    MockManager.Verify();
}

 

Here, we've asked TypeMock to automatically create a mock implementation of the IShippingCostRule interface, and then return it when the Find method gets called. Now, this gives us the ability to verify the correctness of the entire CalculateTotalCost method, with zero dependencies on other objects.

And there you have it, a quick and easy introduction to the concept of mocking. I've really only covered the basics, and especially just the tip of the iceberg when it comes to the abilities of a mocking framework such as TypeMock, but hopefully it should be enough to get the ball rolling :)

Be the first to rate this post

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Comments

Powered by BlogEngine.NET 1.4.5.0

Welcome!

My name is Fredrik Kalseth, and this is my blog - thanks for visiting! I am fortunate enough to work with what I love for a living, and this blog is essentially the biproduct of that.

I work as a senior consultant for Capgemini, and am also an active participant in the Norwegian .NET community, as an avid attendee but also as a speaker (most recently at NNUG and MSDN Live).

As a developer, I have a wide circle of interest. My primary passion is for agile, test-driven development, with focus on best practices and clean code. That said, I also love to work on the frontend, especially with web development.

On Twitter? My handle is fkalseth. On LinkedIn? I`m there too.

Disclaimer

This is a personal blog; any opinions expressed here are my own and do not necessarily reflect those of my employer. All content herein is my own original creation, and as such is protected by copyright law. Unless otherwise stated, all source code posted on this blog is freely usable under the Microsoft Permissive License.

What Readers Talk About

Comment RSS