TDD for unbelievers
I have to admit, I was not-so-good with TDD (Test-driven development). I just didn’t see how it can help me to deliver a better software. Products and solutions I developed were pretty much rock solid and it felt good to see them running for years. What else did I need?
But it was time to give TDD another try. Obviously, it became quite impossible to ignore this subject today, especially when people talk about continuous deployment already!
“Real Developers Don’t Need Unit Tests” (video) does a good job in describing once again what TDD is good for. If you don’t see a value in TDD, like I did – please, do yourself a favor and watch this session.
Some major takeaways:
- I guess the main point is that TDD is not about writing failing tests first, as I assumed for years. It is a way to design and implement a system, not from one’s head or some silly design specification but from the actual needs. Tests are a pleasant side-effect, but what they really do is actually show how the system works. I think it was “Groovy in Action” that initiated an excellent tradition of using
assertsas a way to demonstrate what code does. What describes better the end result?assert "test" == str.test() // Or str.test() // prints "test"
It may sound like an obvious thing but making a mental switch from “Tests for the sake of tests” to “Design and implement through tests” was my first enlightenment as I watched the video.
- There are three phases in doing TDD: Red, Green, Refactor. First, you provide a demonstration of a new feature. It takes a form of a failing test, right. But it is a demonstration of a new feature nevertheless. Then you implement it. And then you clean up, refactor and tidy up. The cleaning process is a critical one! From my experience it is widely and commonly omitted as people get to the “Green” phase and commit. This is exactly where products start getting a bad smell, clarity get lost, things get messy and next thing you hear is “Do not ever touch it”.
- Test behavior, not implementation. Another common belief about unit tests is they should test class methods and state transitions, i.e., current class implementation. The problem with this approach is that tests break each time implementation changes. And instead of updating tests accordingly it is very tempting to comment them out,
<exclude>them from running or simply@Ignore. If one tests functionality and behavior then it shouldn’t break! If there’s a need to test a private members then they probably do too much and should be extracted to their own class and their own tests. “Design and implement through tests” again. - When doing code review start from the tests. Since tests are the answer to the question “What this code does?” it makes sense to review them first to concentrate on a meaningful parts instead of everything. Especially when time is tight and only the relevant code should be reviewed.
- Unit tests are not a substitution to integration tests, acceptance tests and QA processes. As was mentioned above, TDD doesn’t really serve the purpose of testing although it is called this way. It doesn’t test for real and doesn’t try to find bugs, it only demonstrates application’s ability to do something.
- Treat your tests as production code. Tests should not be written as a throw-away code that is never maintained or updated. Tests are application’s user interface, its front page, if you wish. And we wouldn’t like our front page look ugly, would we?
Those willing to pay the extra price of doing TDD can get to it. Those running after new features every two weeks will have a harder time, of course.
P.S.
See a follow-up post “JUnit Updates”.
Wiki Updates Tidying up XML headers



[...] talking about TDD there comes time to bring my JUnit knowledge up-to-speed with 4.x and 4.8.x versions. Also, I see [...]
[...] and automatically. From all the people I have talked to personally, very few are actually sold on TDD or at least try to take it [...]