Advanced mocking: auto-interaction testing


When dealing with legacy systems or those not designed with specific testability scenarios in mind, you have to test your changes in non-traditional means.  In normal mocking (or test double) scenarios, you have some kind of external dependency that you want to substitute for.

For example, you might have a OrderProcessingService that needs to send an email out when an order is completed.  During testing, you don’t want actual emails being sent out, so you hide email sending behind an IMailSender interface, and use an imposter in its place.

But what happens when you’re working in a legacy system, or the difficult component you’re dependent upon is the class you’re testing?  These scenarios are common when modifying legacy code, or you’re extending a third-party component or library.  In these cases, I need to verify interactions of the class with itself, leading to auto-interaction tests.

Modifications needed

We’re trying to extend an order processing system that was built several years ago, and has absolutely zero unit tests.  The business has come with a request to introduce discounts to orders, and need the total to reflect the order.

To make this change, we need to create a DiscountPercentage property on the Order object, and call the UpdateTotal method when the DiscountPercentage is set:

public class Order
{
    private int _discountPercentage;

    public virtual void UpdateTotal()
    {
        //hit database, tax service, etc.
    }

    public int DiscountPercentage
    {
        get { return _discountPercentage; }
        set
        {
             _discountPercentage = value;
            UpdateTotal();
        }
    }
}

Now, for whatever reason, this is the exact change we have to make.  The UpdateTotal method must be called in this architecture to update the OrderTotal on the Order object.  Our resident system experts tell us that UpdateTotal must be called any time changes are made that could affect the OrderTotal.

Not the best architecture, but in legacy systems, we have to work with what’s given us.  So where does the mocking come into play?

Here come the mocks!

When we want to test the DiscountPercentage that calls the UpdateTotal method, we wind up hitting the database, the tax web service, maybe even a sherpa in Nepal.  We could try to fake out all of these dependencies, but nothing in our Order object is built to do this.  Additionally, there are many other places in our system that are in dire need of refactoring, so we can’t commit resources to “fix” the Order class.

Our resident system expert has assured us however, that all we need to care about is that the UpdateTotal method is called, the DiscountPercentage property will work.  So what I’d like to do is create a test that sets the DiscountPercentage, and just makes sure that the UpdateTotal method is called.  I don’t want the real UpdateTotal method actually do its work, as it hits the database and whatnot, but just to verify that the method is called.

####

The manual way

First, I’ll try and do this without a mocking framework like Rhino Mocks.  To do so, I’ll create a test-specific subclass of the Order object:

public class TestOrder : Order
{
    public bool UpdateTotalCalled = false;

    public override void UpdateTotal()
    {
        UpdateTotalCalled = true;
    }
}

I override the method interaction I’m interested in, “UpdateTotal”, and set a flag that simply checks to see if it was called.  I also made sure I didn’t call the base method, as I don’t want to bother that sherpa.  In my test, I’ll use the TestOrder class, and then make sure that the UpdateTotal method was called:

[Test]
public void Should_update_the_total_when_applying_a_discount_the_manual_way()
{
    TestOrder order = new TestOrder();

    order.DiscountPercentage = 15;

    Assert.IsTrue(order.UpdateTotalCalled);
}

Since the DiscountPercentage property calls the UpdateTotal method correctly, my test passes.

Creating lots of these little subclasses gives me great control over the behavior I’m looking for, but it can get tedious having all these little test double classes lying around.  Enter tools like Rhino Mocks (which do many more test doubles than just mocks), that can automate the creation of these test double classes.  So how might we do this with a mocking framework?

Enter Rhino Mocks

Rhino Mocks (and other mocking frameworks) allows you to create partial mocks, which are useful for testing concrete classes.  With partial mocks, the existing behavior of the class being mocked will be preserved, except for members I explicitly set rules on.  To make sure the original UpdateTotal method doesn’t get called, I’ll put an exception in temporarily:

public virtual void UpdateTotal()
{
//hit database, tax service, etc.
    throw new Exception("Shouldn't get here!!!");
}

I’ll take it out after I make sure my test works, but it’s a good gut-check to make sure the mocking works the way I expect it to.  With Rhino Mocks, here’s what my test would look like:

[Test]
public void Should_update_the_total_when_applying_a_discount()
{
    MockRepository mocks = new MockRepository();
    Order order = mocks.PartialMock<Order>();

    using (mocks.Record())
    {
        order.UpdateTotal();
    }

    order.DiscountPercentage = 15;

    mocks.VerifyAll();
}

I create the partial mock by calling the PartialMock method on the MockRepository, telling Rhino Mocks what type to mock with the generic argument.  Rhino Mocks will dynamically create a subclass of Order on the fly, and I don’t have to worry about dealing with another little class lying around.

Because the UpdateTotal method is virtual, Rhino Mocks is able to mock this method.  If the method wasn’t virtual, I’d have to resort to such techniques like subclass and override non-virtual methods.

In the Record section, I call the methods on the mocked Order object, essentially recording what I expect to get called later.  Since I’m in the record phase, calling the UpdateTotal method doesn’t call the real implementation here, proven because no exception gets thrown.

Finally, I set the DiscountPercentage on the Order object and call VerifyAll to verify that all the expectations were met.  The UpdateTotal method was called during the replay phase, so my test passes.  Keep in mind that during execution in both the record and replay phases, the real UpdateTotal method is never called.  Rhino Mocks has overridden the behavior, keeping track of what expectations are set and what has been called.

Summary

Semantically, both testing techniques performed the same interaction test.  All I cared about when testing was that the UpdateTotal method was called, but I didn’t care what the actual behavior is.  For my purposes, UpdateTotal is a black box.  In fact, I went out of my way to make sure that the real implementation was never called.

It’s a matter of personal preference which technique to use.  The goal is to have an easily readable test that I can decipher what I’m testing at a quick glance.  Whether you use Rhino Mocks or manual test double creation is up to the team, and always on a case-by-case basis.  If manual creation is more explicit, I’ll opt for that.  If creating through a mock framework is more clear, I’ll opt use it instead.

Auto- or self-interaction testing is a great technique when you need to modify legacy code or extend a third-party library.  I’ve used this technique quite a bit recently when testing MonoRail Controllers.  It’s never a perfect world in TDD land, so having a few tricks like these up your sleeve can make the journey a little smoother.

Letting the customer drive the demo