The discussion on the future of unit testing for the masses has shifted from the standard “if they are too stupid to learn it, we don’t want them” to “TDD without good design will make really bad tests”. and this is a good thing. it’s a good thing because it secretly implies that if you could write Good Unit Tests, regardless of design, then teaching design as a separate thing should not pose a problem.
Discussion so far:
But first, let’s make one thing clear:
TDD is NOT Unit Testing.
My previous post was not “TDD decoupled from design==adoption”, it was “Unit testing decoupled from design == adoption
TDD is (technically) about when you write the unit test.
You can still write crappy tests in TDD mode. With good design. Unit Tests deserve a good book about them without TDD in it because the current books about TDD suffer from lack of SRP.
On the other hand you can still write good tests, without TDD. The design might make them a little longer, but if you learn to write unit tests well, this should not pose a problem.
Learn Good Unit Testing regardless of TDD and Design
people can start learning unit testing before learning TDD. they learn the silly stuff (the kind udi looks down upon) in an hour, and then they get to the hard stuff : making the tests readable, maintainable and trust worthy. these are separate properties that can be learned to be done regardless of design, since test naming convention, refactoring and correctness can be learned in separate.
The only reason it’s really hard to teach in separate today is because as those devs get to test real world code they have to start dealing with real world dependencies and that it the barrier that usually stops most people. having “intermediate” frameworks in place such as JMockit and Typemock Isolator can help in that regard, keeping people focused on the task at hand and deferring the need to learn other types of design for a time that is better. The idea is to let the developer choose when to learn which technique:
- Learn how to write good unit tests (book)
- Learn Good Design technique (give me a link to a good starter book!)
- Learn Test Driven Development (book)
I want a developer to grok each one of those things to a very deep level, but today’s “market” wants them to learn it all in one go. Since each one is its own little art form, are you really surprised to learn that most of the mass population is not there yet?
If people think that the only way to write good unit tests that are not worthless is by doing them TDD style with SOLID design, they are showing several things to me:
- they don’t get what “good” unit testing is
- They don’t “get” what value good tests have outside the context of TDD
- they guide a community who reads them down a path of “all or nothing”. which for most people begets “nothing”.
“If logic is duplicated, if the code is tightly coupled, if there is no separation of concerns, the unit tests will be useless - even if they “test” the class in isolation.”
That is wrong in many levels. Let’s start with the fact that a unit test can have a specific value in testing a specific class in isolation, even if the bugs in that class are duplicated on other classes. If Udi does not agree on that, I don’t know what else to say about that. I wish that what he meant was that all these problems were repeating in the tests, since this is usually why people fail when they start out unit testing: they write crappy tests with bugs, code duplication and lack of isolation (this can all be learned). But he’s not. It feels like a “purist” view that does not reflect the real world. It must be nice living in an echo chamber!
Let’s see udi contradict himself in the same post:
“Managers shouldn’t necessarily sacrifice their projects on this altar of learning. Organizations need to find ways for developers to safely practice these techniques as a part of developing their “human resources”. First of all, this needs to be communicated to everyone - that the organization understands the importance of these techniques, the desires of developers to adopt them, and the projects that need to be delivered.”
“…It’s a gradual process.”
That’s the problem Udi. It’s not possible to do it gradually today, because people keep saying that you can’t do things in little chunks. you have to learn it all together. If we were to help developers learn what good unit testing means they could much more easily learn that stuff, and then learn the other stuff.
“It is not a technical challenge to write a unit test, any half trained monkey could do it. A few attributes, a couple of classes, a few new() statements, and a few Assert statements. We don't need magic mocking frameworks, we don't need any mocking frameworks for 90% of our tests, we don't need application of 12 GoF principles before we can write a test, honestly.
Testing and writing automated tests is hard because it requires a strong understanding of the user stories that sit behind your code and project, because it requires you to think as a user and not as a developer, and because it requires you to be able to think of multiple conflicting axioms, test cases and class interactions, and how to cover the weaknesses of each individual test with other complementary tests.”
Casey preached about what he sees as the “end game” for unit testing, TDD and Design. where everything is in one great ball of goodness. Or did he?
Let’s separate these points into better chunks:
Design related stuff:
- to think of multiple… class interactions
Good Test related stuff:
- Understanding of the user stories
- Think as a user not a developer
- think of multiple conflicting axioms (..?) test cases..
- how to cover the weaknesses of each individual test with other complementation tests.
TDD related stuff
So, what I gather from casey’s words is that you want your tests to be :
- testing the right thing
- be readable and show intent
- have good coverage
- test or be aware of class interactions (the design related stuff)
except the last point which is where most of today’s mock frameworks force you to redesign, there is nothing here you can’t learn separated from TDD and SOLID techniques. the interaction stuff is where those other isolation frameworks I mentioned come into place.
We need to decouple Good Unit Testing from TDD and SOLID. And it seems that not only “noobs”, as a stupid idiot commented thoughtfully on my last post, can benefit from learning this distinction.