I have seen many articles on why Test Driven Development is good and that it reduces development time and so on. But after searching through a lot of forums, I am still yet to get a concrete advantage of TDD. I am not saying testing is a bad thing, but my point is what is the harm if I write my unit test after I write my source code rather than vice-versa as TDD proposes. And both the test cases do act like regression tests once it is complete. I also experienced a lot of problems while trying to follow TDD in a legacy code.I guess nowadays most of the code is legacy code where we have to modify code without pre-existing tests. Also is TDD limited to unit tests only or even system level and integration tests. I am just not able to imagine how we can do integration tests without writing source code.
Let me answer by asking a rhetorical question:
If you were ever to write software, wouldn't you start by, say, gathering and writing down requirements for your software?
The basic tenets of TDD imply that your test cases are your requirements. Therefore, by writing down your tests first, you are writing down your requirements first. You're just doing it in a different way.
Now is this the best way to do things? That's subjective. But that's essentially why TDD writes tests first.
If you write your tests after writing your code (especially code that you've written), the danger is you end up writing tests that you know the code will pass, rather than writing tests that ensure correct behaviour. Like writing your requirements document after you've already developed the software.
Also, Test-Driven Development doesn't necessarily mean that you write all your tests and then sit down and code up something that meets them. OFten, you'll write tests, then write code that passes those tests, and iterate that process.
I also experienced a lot of problems while trying to follow TDD in a legacy code.
This is one reason why it is often better to write the test before you write the code that you are testing. If you write your code and then afterwards try to test it, you may find that you need to redesign or completely rewrite your class to make it easier to test. If you write your test first, you encourage yourself to write a clean, testable interface to your classes.
Writing the test first ensures that it's actually possible to unit test the System Under Test (SUT).
If you write the test afterwards, you will discover that in many cases you can't unit test the SUT because you have made assumptions about the run-time environment that may not be true.
I won't say that TDD shorten the development time. It could even be longer. But TDD leads to "clean code that works". The software grows at the same time as the unit tests, not one after the other, and thus is tested as soon as it it written. This gives confidence to the developer as well as a good idea of "where he stands" because he knows that what he has done so far is "done done".
Also writing the unit tests after the fact, can be hard. The author "Working effectively with legacy code" (a very good resource BTW) even says that code written without unit tests indeed is legacy code.
Also is TDD limited to unit tests only or even system level and integration tests. I am just not able to imagine how we can do integration tests without writing source code.
TDD is a development technique, it's not intended to replace other kind of testing.
One can however write integration tests before the code to be tested exists. This allows asking oneself how the code that will be produced can be tested.
Writing test first puts you in the shoes of the "client" of a software unit. If you try and write tests first, you will tend to write the code that is the easiest to use, as opposed to the code that is the easiest to write.
When writing tests first, I also tend to get into the mindstate where you try and imagine "hey, what should I do if I pass this, this, or that to this method", hence having one more, last time to think about the design, requirement, etc... before I've spent too much time writing code that ends up being useless.
But true, sometimes you just have so little idea how you're going to code something, you just have to go and write it, then write some tests, and maybe refactor. That's ok. As long as in the end you get a sensible design, clean enough code, and tests to save the day when regression happens...
And of course, to write integration tests, you must have code to integrate, so that's hard to completely TDD it (but maybe, writing the integration test gives you a good idea of a modules interface, and can serve as a preparation for unit tests.)
I think one of the concrete advantages is that you don't tend to write more code than you really need to. At least that's how the theory goes. With TDD you start with writing all the tests you think you need to solve a specific requirement. Then you write just as much code as you need to make all tests pass. I couldn't say for sure whether this actually results in better code, but it saves you from waste time fiddling with code because you don't realize that you're already done.
Also, the difference between writing tests before or after writing the code is that when you write tests before you actually think about what you need to solve the problem, whereas when you write tests after the code you run the risk of just representing the code in tests.
I also experienced a lot of problems while trying to follow TDD in a legacy code.
The problem with TDD and legacy code is well-known. Every book or essay I've read about testing specifically points out that it is a lot harder to apply TDD to existing code.
Basically, this is not a problem that only you have and it has been recognized by TDD-defenders. I think one of solutions is to slowly start applying TDD to the parts of the code you're working on anyway and not diving right in and being overwhelmed.
Where I work, we do a lot of unit testing, but we don't strictly follow TDD. However, what I found helps to get the hang of TDD is following its rules when you fix a bug. It's usually easier to come up with a test for a small problem and see how TDD can help finding the problem and fixing it than when you try to apply TDD to a huge feature.
But after searching through a lot of forums, I am still yet to get a concrete advantage of TDD.
I learned the principles of modular design by practising TDD. I gradually increased my skill in detecting and removing duplication, detecting naming problems, isolating code into reusable engines and keeping dependencies loose. Practising TDD gave me a way to learn all those skills over time. I consider that the single greatest concrete advantage of TDD.
You can read more about why TDD works here: http://bit.ly/peWDS