Monday, March 16, 2009

Removing collaborator dependencies in unit tests

I encountered a neat little design problem the other day, and although I’m sure many people have encountered something similar before, I thought I’d share in case there’s anyone (like me) who hasn’t seen it. This is specifically addressing the use of Rhino Mocks with C#, which is what we use at my company.

So I’m writing unit tests for a class, let’s call it Foo, and many of the public methods in this class create a new object of type Bar. The issue is that this object is created inside the method, and isn’t parameterized, so for example we have:


public class Foo{

public method1(){

Bar myBar = newBar();

//do stuff with myBar

}

//and several other methods that create a new instance of Bar

This is a problem for a few reasons:

1. I want to test Foo’s methods in isolation

2. Bar already has test coverage

3. Bar has many other dependencies that take time to mock out (and creates code duplication with the existing test coverage)


The standard way of doing this would probably be to parameterize myBar. However, it doesn’t strike me as very elegant to have to change the parameter list at every call site of Foo’s methods. If/when C# gets optional parameters, that won’t be so bad.


A bit of Googling found me this article. It’s written for Java, but it’s well-written and I was easily able to translate it to C#. The idea is that we replace the call to Bar’s constructor with a factory method (super easy with Resharper), and then override this factory method in our test. e.g.:


public class Foo{

public method1(){

Bar myBar = CreateANewBar();

//do stuff with myBar

}



public Bar CreateANewBar(){

return new Bar();

}

}

Now the only hitch is how to override CreateANewBar() in the test fixture. At first I thought I could use a delegate, and reassign that instance method on-the-fly – but I guess C# can’t do that; opening up defined classes is a gateway drug to Ruby you know. The next best thing as far as I can tell is to just derive a new class from Foo and use method hiding to override the functionality of CreateANewBar(). You return a mock Bar object in the hiding method (remember to extract an interface for Bar if one doesn’t exist already), and so it ends up looking something like this:


[TestFixture, Category(“Standalone”)]

public class FooTest{



public IBar barMock = mockRepo.CreateMock<IBar>();



public class DerivedFoo : Foo {

public new Bar CreateANewBar(){

return barMock;

}

}

//perform all tests on DerivedFoo instead of Foo

}

And there you have it. One of my coworkers I shared this with mentioned that this would be much easier by just calling Expect on IBar's constructor. However, I don't think this works - Rhino Mocks can't just magically intercept calls like that. If I'm wrong, please let me know.

May or may not contain ducks

So all the cool kids have a blog these days, guess I should join the party.