jimmy keen

on .NET, C# and unit testing

How to mock private method – solutions

January 25, 2015 | tags: unit-testing mocking c# design

I one of my previous blog entries I explained why it is not possible to mock private methods with tools like Moq or FakeItEasy. In this post I’ll show how you can overcome such situation1.

Problem: Origins

First, it is important to identify source of the problem. When you say 

I need to mock this private method

All I can hear is

This class is poorly designed. I must use some workarounds or even ugly hacks in order to test it. I know I shouldn’t be going down that road, but it seems I have no choice.

Properly designed SOLID code will never put you in a position which will require you to do private mocking. Source of the problem? Bad design.

To better understand my point let’s take a quick look at a class building order XML. Suppose you want to test CreateDocument method:

public class OrderDocumentFactory
{
    public XDocument CreateDocument(Order order)
    {
        var document = new XDocument();
        document.Add(new XElement("Order",
            new XElement("Date", order.Date.ToShortDateString()),
            new XElement("OriginalValue", order.TotalValue),
            new XElement("Discount", CalculateDiscount(order))
        ));

        return document;
    }

    private double CalculateDiscount(Order order)
    {
        var promotionsFileName = string.Format("P_{0:ddMMyy}.TXT",
            order.Date);
        var promotionsFileContent = File.ReadAllText(promotionsFileName);
        var baseDiscount = double.Parse(promotionsFileContent);
        var isLateProcessing = (DateTime.Now - order.Date).TotalDays > 3;
        var bonusDiscount = isLateProcessing ? 10.0 : 0.0;
        var totalDiscount = baseDiscount + bonusDiscount;

        return order.TotalValue * (100 - totalDiscount) / 100.0;
    }
}

CreateDocument is trivial to test if we can mock this discount calculation thing. With all the file-loading, date-parsing and what-not, it simply gets in our way. This is a lot of stuff we do not really care about, we should mock it. But we cannot. What to do then?

Design considerations

Single responsibility principle, first of the SOLID principles states that:

Every class should have a single responsibility (a reason to change - JK), and that responsibility should be entirely encapsulated by the class

In other words, class should do one thing and one thing only. OrderDocumentFactory, what does it do? It builds XML. If our requirements evolved so that we need to return slightly different XML, that is our one reason to change the class in question. Building XML is our single responsibility.

Unfortunately, OrderDocumentFactory also has second, hidden responsibility – it calculates discount. Had we decided bonus discount is no longer supported, we’ll have to modify OrderDocumentFactory class. This is strange because why would document factory had anything to do with discount calculation? If we wanted to change discount calculation logic we should be rather looking to modify DiscountCalculator class. And there goes our problem – we have one class pretending to be two2.

SOLID solution

We already know what to do. We need a second class that will handle discount calculation logic. All right then, is this code unit testable now?

public XDocument CreateDocument(Order order)
{
    var document = new XDocument();
    var discount = new DiscountCalculator().CalculateDiscount(order);
    document.Add(new XElement("Order",
        new XElement("Date", order.Date.ToShortDateString()),
        new XElement("OriginalValue", order.TotalValue),
        new XElement("Discount", discount)
    ));

    return document;
}

Not so fast. This “solution” adds another responsibility to CreateDocument method – instance creation. We do not want that. What if DiscountCalculator required some constructor arguments? Where would CreateDocument take them from? Instance creation is almost always out of scope of any class responsibilities. We need dependency injection:

public class OrderDocumentFactory
{
    public OrderDocumentFactory(IDiscountCalculator discountCalculator)
    {
        this.discountCalculator = discountCalculator;
    }

    public XDocument CreateDocument(Order order)
    {
        var document = new XDocument();
        var discount = discountCalculator.CalculateDiscount(order);
        document.Add(new XElement("Order",
            new XElement("Date", order.Date.ToShortDateString()),
            new XElement("OriginalValue", order.TotalValue),
            new XElement("Discount", discount)
        ));

      return document;
    }

    private readonly IDiscountCalculator discountCalculator;
}

With code structured like this you don’t have to mock private method but instead you mock dependency, IDiscountCalculator, which is the usual course of action.

Conclusion

In most of the cases the need to mock private method originates from poor design. Design that is already causing problems (inability to write unit tests) and will cause more problems as the code grows. Solution is simple:

Unit tests are much like your good buddy. When dealing with your code they will be first to ask “Wait a second, this cannot be right?”. Mocking private method cannot be right. And it is not.

  1. We have to make important assumption here - you can change problematic code.

  2. Private CreateDiscount method is a class in disguise.