Yes, we should avoid mocks of mocks. But building small pieces of code that have little knowledge of their surroundings, and testing them independently, is no panacea.<p>You can see this problem in any Java Enterprise shop that has code coverage as a religion: To make it possible to cover all that code (including all the boilerplate caused by the technologies selected), then we end up with a billion little classes that are managed by some kind of dependency injection system. Hundreds of thousands of lines of Spring XML configuration files, or their equivalent in annotations. Every piece is tested, but are all the pieces tested together, automatically? We quickly get into extremely large and expensive automation suites, or a whole lot of things that aren't really tested regularly, making all those unit tests a lot less valuable.<p>We can't wish complexity away: Make every unit too small, and the management of the units is now your new problem. You head in the same direction with the whole Microservices context.<p>A maintainable system is one built of components that are just simple and cohesive enough to be understandable by a human, but not any simpler. The right modularization is the hardest thing we do in software. The right size is hard to gauge, modules like that might be hard to name, and they are often hard to test. Sometimes one of those aspects must suffer for the others to do well.
Reducing the knowledge of internal structures is what the Law of Demeter (<a href="http://en.wikipedia.org/wiki/Law_of_Demeter" rel="nofollow">http://en.wikipedia.org/wiki/Law_of_Demeter</a>) is about. Usually good practice.
Well, one thing I learned from all this recent TDD related discussion is that almost nobody is aware of this book [1] and the entire school of TDD it spawned.<p>[1] <a href="http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627" rel="nofollow">http://www.amazon.com/Growing-Object-Oriented-Software-Guide...</a>