A few years ago I gave a talk that gets into the "why" of the relationship between testability and good design: http://vimeo.com/15007792
It has a rambling start because I was timezone shifted, but gist of it is that whenever we encounter something that makes testing difficult there's some sort of design problem that is causing it. Some are obvious and some aren't.
- Hard to test a class in isolation -> too many dependencies
- Tests fail intermittently -> mutable global variables
- Unable to find a good point to test -> direct access of system externals, i.e., no layering
- All tests can't run because of resource leaks -> code doesn't clean up after itself
- Urge to test something private in a class -> usually an SRP violation
- ...
The list goes on.
The real question is why? Why is testability a proxy for good design?
I think that the reason it is is because the essence of good design is creating things that are understandable - understandable enough to see plainly what they do and understandable to enough to modify and extend.
Automated testing is a cognitive process - it is writing code that understands code. Every step of test is bit of that cognition. If it's hard to write code that "understands" your code, then it's probably hard to understand your code.
I don't quite buy the contrapositive, though: I easily understand small functions that touch well-named global variables, as long as it touches maybe 1 or 2 of them, but we wouldn't call such a function particularly "testable". At some point, poor testability and difficulty in understanding correlate, but we can easily exhibit entire classes (ha again!) of easy-to-understand-but-difficult-to-test code.
If we had a catalog mapping test/testing problems to design smells, perhaps we'd find it easier to argue our position more convincingly. A bunch of us keep meaning to write that catalog, but I haven't seen it yet. :)
That seems true. But most TDD people do not claim that, they claim that it it's hard to write fast code that "understands" your code without needing to "understand" anything else on the system, then it's probably hard to understand your code.
I can't agree with the fully qualified proposal.
A great example of this is Bob Martin saying that you are absolutely doing it wrong if you don't write your tests before your code and if you don't restrict your writing of app code to the pure case of making a failing test which you wrote first pass. This is an extremist ideology, and many of us are tired of having this thrown in our face over and over again.
Here is Bob saying this: https://www.youtube.com/watch?v=WpkDN78P884&feature=youtu.be...
No one said, "testability is a meaningless goal", and it's dishonest to say that. We're saying that the extreme to which the TDD crowd takes this good general guideline is bad, and their insistence that anyone who doesn't do it that way is doing it wrong is growing very tired and someone has to speak up against it.
That said, I understand meeting extremism with extremism. I don't think it works, but I understand it.
http://benlakey.com/2014/05/04/testing-is-science/
I don't think I'm overstating it.
Trading some small downsides for big upsides may be a gain, but forgetting about the cost is a huge mistake.