27 September 2006

Mocks driving an SRP(*) design

Earlier this month, there was an interesting discussion on the Test-Driven Development list. avinap77 was reflecting on test-driving his code using mocks. Later on, he posted this to the list.
[...] I also realized that an expectation is more than just expecting a method to be invoked - it's also the paramaters that are sent to it and what happens with the method's result. In the example, my class needed to invoke a getCustomerDetails() method on the IDatabase collabroator, send it the appropriate ID as a paramater, and then send the resulting customerName to another collaborator (the IHtmlFormatter), and finally return the formatter's result - so this is in fact testing four different operations. I also found that these "smells" turn up pretty early - as soon as I'm trying to write a test with too many interactions, that's the immediate "red light" that the class has too many responsibilities, and I immediately start writing a more focused test which introduces more focused responsibilities represented as narrow interfaces (such as replacing the IDataBase with the INameProvider in the example). This is opposed to some state-based "baby steps" examples I've seen where the splitting into responsibilities might come later during refactoring. Do you find this too when using mocks/interactions?
This is the experience we keep trying to convey when promoting Mock Objects as a technique, with limited success. It forces you to think about what the pieces should be and where they go. One of the real hurdles to working well with Mocks is to realise that the point is not to reproduce interactions with existing types, but to force the discovery of new types. (*) SRP Single Responsibility Principle

No comments: