Don't get me wrong, this is not another "You should practice TDD because.." post. This one is aimed for those who want to start test-driving, but needs some guidance on how to get the maximum benefit and avoid the typical disasters. I plan to write several posts about various kinds of tests and when to (not) use them. Different kinds of tests (and testing practices) provide different benefits, and I thought maybe I write this as a cornerstone kinda post and refer to it from time to time.
So, these are the promised virtues, in chronological order.
Tests help you design the API of your class
You might have fancy ideas about your methods and properties, but the users who actually use your stuff think otherwise. Hate mail follows.
Be the first user of your class before you even wrote it, and you'll make it right before anybody else sees it.
Tests help you design the architecture of your system
You think you're smart. Those DML diagrams make your mama proud of you. Until you get back to your app after a year or two and have to make a couple of changes. You discover a couple of 2000 LOC methods, goto statements, and even stored procedures. Gods, what a mess!
There's no rigorous proof, but numerous sources tell us that test-driven design is much more flexible and maintainable. There are several reasons to believe that, and it's worth a separate post. Anyway, if you stop pretending you're failproof, and start listening to your tests, you might improve your design beyond your wildest dreams. This is considered the most important benefit of TDD, although not obvious from the beginning, since this is not directly related to "testing".
Tests help you implement the members of your class
Test-driven, your method eventually becomes The Simplest Thing That Works. Most of what wa said above applied to member-level design as well.
With tests, you are sure that your application still works correctly after you change it
After making a little change to the underlying implementation of a particular minor feature, you manually test the whole system.. or your end users do that for you. Either way, you spend the weekend trying to get the corrupted data from a backup you accidentally made a couple of days ago. (I'm not making this up, it actually happened to me!)
Tests, when done properly, can be a safety net that protects you from such unfortunate accidents. You can freely refactor your code in order to further improve your design, and not afraid to introduce a regression bug.
Tests document your API
When structuring your tests around classes (which is not the best idea, but is ok for a start), you can look at a particular test and understand what the corresponding method does. That is, if the test is named and written appropriately (I promise a post on this).
Tests document your system
This is not the same as the previous one. When looking at a new system, I'm trying to figure out how to do stuff with it, not what a particular class does. So, when structuring your tests around the features of the system, you provide a nice way of documenting its behavior, both "how to use FeatureX" and "what happens if I actually use it".
Is it seven already?
If you know other benefits, please please write them in the comments!
Ok, now what?
Hopefully you don't use TDD just because the Alt.Net guys told you to, but because you want to get certain sweet stuff out of it. Now that you know these benefits, you don't do it blindly. You try to write your tests so that they make refactoring easier, not harder. So that they actually influence your design, and not the other way. So that they are easy to understand, and make you understand the system even if you're a total stranger.
How do you achieve that? Oh, that a different story..