One of the less stated benefits of doing TDD is that it concentrates your mind on the problem.
Recently I was looking at a section of code which was creating a Lucene search string from criteria passed in from the user. I needed to add some new functionality, but it was a bit higgledy-piggledy so following the broken windows principle I decided to refactor it to the builder pattern before I added my new feature.
I ran NCover on the code and it reported 70% coverage which considering what I knew about the history of the system was surprisingly high. I decided there was enough coverage, paired with a colleague and dived in. At first we were doing well. Our changes broke the tests a few times which reassured us about the coverage, but after a while it felt that we were losing a bit of steam. We’d done a lot of refactoring but it didn’t feel like we’d got very far.
Skip to a couple of days later - I’d not been able to touch the code and neither had my colleague who had now been taken off to deal with another project, so I pulled in the other dev on my team who is probably the most fanatical TDD nut I’ve ever met. Immediately he was uncomfortable, he’d quickly spotted the tests were really only integration tests (something I had put to the back of my mind) and got jittery as we continued from where I’d left off. I didn’t like to see him in so much pain so quickly relented and let him write new tests even though I felt it was just going to slow us down, maybe even to the point where we wouldn’t get it finished. However he assured me that although it felt slow now we’d be racing along soon enough.
Not only was he right about that, but as we were doing it the objective was so much clearer. Writing the new tests meant we were forced to really think about each move we made so our refactoring had clear direction. We spent about the same time working on the problem but probably made twice as much progress as my previous attempt and ended up with a proper unit test suite around the code.
Some day soon people are probably going to do away with the need to do TDD, which I think will be a shame as it never ceases to amaze me how many benefits it has.
After Mini Spa this year I was fortunate enough to get to chat to Nat Pryce in the bar. He mentioned some interesting projects he’s working on, such as something I think he called “Domainatrix” - a tool you can use to analyse your code to see if it is relevant to the domain. Very nice chap.
Having used NMock (which he helped write) extensively I asked him if anyone was looking after it as there hasn’t been any visible activity for a while. It turns out that Thoughtworks took it over as of release 2.0 but have clearly decided not to support it anymore.
If you’re still using it I highly recommend you start looking for a new mocking tool ASAP.
I’ve recently started using RhinoMocks instead of nMock, mainly because it’s strongly-typed. However, I’ve found a few other little treats:
Stubs
In nMock, if you want to stub some method calls on a mocked interface you have to do something like this:
Mockery mockery = new Mockery();
IService mockService = mockery.NewMock();
Stub.On(mockService).Method("MethodA");
Stub.On(mockService).Method("MethodB");
Stub.On(mockService).Method("MethodC");
...
Which is cumbersome and noisy. In RhinoMocks you can do this:
MockRepository Repository repository = new MockRepository();
IService serviceMock = repository.Stub();
...
…and RhinoMocks will ignore all calls to that interface. This is really nice as you generally only test the SUT’s interaction with one dependency at a time.
Dynamic Mocks
If you only want to test one interaction with a dependency and ignore all others you can create a dynamic mock.
MockRepository Repository repository = new MockRepository();
repository .DynamicMock();
...
All calls to the mocked dependency will be ignored unless they are explicitly expected (e.g. Expect.Call(mockService.MethodA)…..). This is the same as not saying mockery.VerifyAllExpectationsHaveBeenMet() in nMock. It’s always annoyed me that you have to remember to do this in nMock and I much prefer that the default for RhinoMocks is to fail when encountering an unexpected method call.
Raising Events
nMock does not natively support raising events, which is a pain, but there are ways around it (I’ve extended his example to support custom EventArgs which you can download here). With RhinoMocks it’s much simpler. Rather than explaining it myself, check out J-P Boodhoo’s great example here.
I’ve being doing TDD for a year or so and the part I have struggled with the most is testing private methods. Should you test them at all? If so, how do you test them?
Michael Feathers’ book “Working Effectively with Legacy Code” has this to say about it:
“This question comes up over and over again from people new to unit testing: “How do I test private methods?”. Many people spend a lot of time trying to figure out how to get around this problem, but [...] the real answer is that if you have the urge to test a private method, the method shouldn’t be private; if making the method public bothers you, chances are, it is because it is part of a separate responsibility: it should be on another class.”
