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.
You probably need Dependency Injection. Pass a BarFactory instance to the constructor of Foo, and use a stubbed BarFactory version that returns a Bar mock in your tests.
ReplyDeleteDefinitely easier with Ruby :)