For more counter-intuitive banter, subscribe to my feed: http://feeds.feedburner.com/jeffreypalermo
There is quite a bit of talk lately about unit testing using the extract method and override, or “inherit & override” method for stubbing out a method for unit testing. Methods don’t have dependencies, and methods aren’t dependencies.
Objects are dependencies, and object have dependencies. One object will depend on another object. Objects are cohesive and present a contract of behavior so other objects know what behavior they can reliably leverage. Because an object is cohesive, everything necessary to perform all its behavior can be passed into the object’s constructor at the beginning of the object’s life. Then, that object can perform all of the operations.
In order to test a particular object, I might have to pass some fake objects (stubs, mocks, etc) into the constructor, but the object under test doesn’t care as long as the type is satisfied. If I can’t test an object by passing in fakes to the constructor (and I can compromise sometimes by using setter injection), then the object is less than cohesive, and I should search the design of the object for an extra concern that is trying to get out. Once I find the extra concern, I would separate the concern (separation of concerns) into its own object and have than as an explicit dependency by requiring it be passed into the constructor (dependency injection).
Michael Feathers outlines this extract method and override testing technique in his book, “Working Effectively with Legacy Code”, and I’ve used the technique many times to break nasty dependencies on legacy code in order to get it under test. This is necessary because legacy code can’t be safely refactored until it has a safety net of test coverage.
If your unit test has to know that another method on the same object is being called, then the unit test knows too much about the implementation of the object. The unit test should be doing black box testing on the object under test. In other words, the unit test shouldn’t care about what code is written or if 1 method or 10,000 methods inside the object are actually called. The unit test merely sets up explicit object dependencies and test state, interaction or both.