... a software development technique consisting of short iterations where new test cases covering the desired improvement or new functionality are written first, then the production code necessary to pass the tests is implemented, and finally the software is refactored to accommodate changes. The availability of tests before actual development ensures rapid feedback after any change. Practitioners emphasize that test-driven development is a method of designing software, not merely a method of testing.
To me it's simply writing your unit tests, before implementing your classes. It's supposed to help you think about the design and in particular the interface of your classes upfront. I like this notion a lot! Thinking before coding - that's a good thing, right? Before I start my ramblings, let's here what Cédric Beust, co-founder of the TestNG framework has to say about TDD:
... When you do TDD you tend to promote micro-design over macro-design. Micro-design means that you are focusing heavily at a very fine level which is the method....but what I found is that after a few years programming you start getting a good feeling with intuition, right away when you're solving a problem of what these extra classes are going to be, what the architecture, the design, the inheritance, how they interact with each other. But TDD is preventing you from going too far ahead...it leads you to create things that are so small that you end up throwing them away because they are really a first iteration and then you modify them and then you rewrite your test. So to me that's micro-design. Macro-design is more when you start thinking: "I'm going to need this interface, I might as well write it now, I'm going to need this extra class, I'm going to write it now; it's going to be empty right now". And those are things that are frowned upon by test-driven development practices and that bothered me a little bit.
The statement is taken from an interview at InfoQ, if you are interested in the verbatim version of this quote, jump to question 6.
So basically Cédric spilled out exactly what my problem is with TDD! I've tried it - really, but writing my tests before implementing my classes just doesn't work for me. Let me tell you why.
I see coding as an iterative and incremental process, Cédric calls it macro-design. You have this basic idea of what your class is supposed to do. In the first step - or iteration therefore, you give it a name, which is supposed to denote the concept of your class. Maybe you also add some javadocs to explain your brainchild. At this point you probably don't have any methods yet. You don't really know in detail how your class is going to work, thus you can't generate your test cases. Most likely you don't want any test cases at all and that's exactly where the experts disagree.
Most of the time, in my experience, a unit test of a class reflects its behavior. You can implement a black box test, but as soon as your class doesn't stand alone, you have to mock the behavior of your collaborators. I'd argue that in 90% of all cases your class collaborates with some other classes or components. So if you start coding your test cases upfront, your not only defining the interface, but also the behavior of how your implementation collaborates with dependencies. If you are working on a component with several different classes and you are starting with implementing test cases upfront, you find yourself constantly refactoring those tests as your implementation evolves. I believe that's not what you want to spend most of your time on.
It's almost a paradox: you need test cases and it's sounds reasonable to write them before your implementation, because then they actually exist and you cannot forget about them. At the same time it doesn't make sense to test something, which doesn't exist yet or you only have a rough idea of how it's actually going to look like.
I like unit tests and I try to write one for each class I put out there. Some people argue, that writing your unit tests upfront increases the quality of your code. I think it's not the unit tests, it's merely giving some thought about your design, before starting to code. However, when I'm in the middle of an "implementation spree", refactoring test cases is one of those annoying and tedious little things that you constantly have to deal with as a developer. And those little things kill the mood - big time.