TDD: Hand written stubs vs Framework generated stubs
A few months ago Uncle Bob wrote a post about TDD where he suggested that he preferred to use hand created stubs in his tests wherever possible and only resorted to using a Mockito created stub as a last resort.
I've tended to use framework created ones but my colleague Matt Dunn and I noticed that it didn't seem to work out too well for us writing some tests around a controller where the majority of our tests were making exactly the same call to that repository and expected to receive the same return value but a few select edge cases expected something different.
The edge cases came along later on by which time we'd already gone past the stage of putting the stub expectation setup in every test and had moved it up into a setup method which ran before all test.
We tried to keep on using the same stub instance of the dependency which meant that we were trying to setup more than one stub expectation on the same method with different return values.
[TestFixture] public SomeControllerTests { private ITheDependency theDependency; [SetUp] public void Before() { theDependency = MockRepository.GenerateStub<ITheDependency>(); theDependency.Stub(t => t.SomeMethod()).Return(someResult); controller = new Controller(theDependency); } .... [Test] public void SomeAnnoyingEdgeCaseTest() { theDependency.Stub(t => t.SomeMethod().Return(someOtherResult); controller.DoSomething(); // and so on... } }
We were struggling to remember where we had setup the various return values and could see a few ways to try and reduce this pain.
The first was to extract those edge case tests out into another test fixture where we would setup the stub expectation on a per test basis instead of using a blanket approach for all of them.
This generally works pretty well although it means that we now have our tests in more than one place which can be a bit annoying unless you know that's what's being done.
Another way which Matt suggested is to make use of a hand written stub for the tests which aren't bothered about the return value and then use a framework created one for specific cases.
The added benefit of that is that it's more obvious that the latter tests care about the result returned because it's explicitly stated in the body of the test.
We found that our tests were easier to read once we'd done this and we spent much less time trying to work out what was going on.
I think framework generated stubs do have thier place though and as Colin Goudie points out in the comments on Uncle Bob's post it probably makes more sense to make use of a framework generated stub when each of our tests returns different values for the same method call.
If we don't do that then we end up writing lots of different hand written stubs which I don't think adds much value.
I still start out with a framework generated stub but if it's becoming overly complicated or repetitive then I'm happy to switch to a hand written one.
It'd be interesting to hear others' approaches on this.
[...] wrote previously about my thoughts of where to use each of the two approaches and one example of where hand written stubs seems to make sense is the [...]
TDD: Thoughts on using a clock in tests at Mark Needham
15 Jan 10 at 10:01 pm
I'm not familiar with Mockito, but I use jMock quite frequently. I often find myself writing:
@Test
public void testSomething(){
expectSomethingWillHappen()
service(findFromList(someList));
}
@Test
public void testSomethingElse(){
expectSomethingWillHappen()
service(findFromList(differentList));
}
private void expectSomethingWillHappen(){
IrrelevantObject dummyObject = new IrrelevantObjectBuilder.build();
context.checking(new Expectations(){{
one(dao).findobject(with(any(List.class)));
will(returnValue(dummyObject));
}});
}
This pattern works really really well, and is a lot more simple than hand-created mocks.
David Ron
16 Jan 10 at 12:38 am
[...] This post was mentioned on Twitter by Mark Needham and planettw, Craig Taylor. Craig Taylor said: RT @markhneedham: handwritten vs framework generated stubs – some thoughts – http://bit.ly/4SxK3C [...]
Tweets that mention TDD: Hand written stubs vs Framework generated stubs at Mark Needham -- Topsy.com
16 Jan 10 at 7:26 am
[...] Mark Needham raps about framework-generated versus hand-written test stubs. The few times I used a tool to auto-generate anything about my unit tests was with Jtest, and the [...]
Helltime for January 18 « I Built His Cage
19 Jan 10 at 4:03 am
I think using generated Test Doubles is a symptom that abstractions are efficient, as their method's behavior is forced to be simple. That said, often hand written stubs are more expressive.
Giorgio Sironi
19 Jan 10 at 10:44 pm
You could skip the Setup and fields and have a method that returns a controller (or a dependency, then create the controller in the test methods). Adjust as needed for your cases and add new methods as needed. Basically refactor your unit tests to remove duplication.
private Controller GetController(int dependencyResult)
{
ITheDependency theDependency = MockRepository.GenerateStub();
theDependency.Stub(t => t.SomeMethod()).Return(dependencyResult);
return new Controller(theDependency);
}
Bill Sorensen
22 Jan 10 at 7:41 pm
[...] wrote a couple of weeks ago about my thoughts on hand written stubs vs framework generated stubs and I noticed an interesting situation where it helped me out while trying to simplify some test [...]
TDD: Simplifying a test with a hand rolled stub at Mark Needham
25 Jan 10 at 9:24 pm