My biggest argument in favor of writing tests is to ensure my code doesn't break relative to other people's code. There are many times I've encountered an update to a ruby gem with no major or minor version change that has broken a, usually implied, contract with my code. I say implied, because duck typers, at least what I've seen in the ruby world, tend to be slack about formalizing interfaces. I write tests to protect against that sort of thing.
You don't, but once you discover it, you write a regression test to make sure it doesn't come back.
However, IANATDD, I am not a test-driven developer - I don't see any reason to be dogmatic, but I do think unit tests can be extremely valuable. So this answer might not be TDD-approved.
"You don't, but once you discover it, you write a regression test to make sure it doesn't come back."
Sure, that's SOP in any good dev. house that does testing. But you've failed to address a key weakness in TDD. The real question is how do you discover these sorts of defects given that a single developer writing in a TDD style is unlikely to do so? TDD is clearly not a cure all, and this is a major weakness of it. Other development techniques, many of which can complement TDD, such as formal code reviews and beta testing can do a better job of getting you to higher product quality than TDD alone.
Who said it was?
TDD is a design technique, not a testing technique.
TDD does force you to think about the interface of your abstraction, however. If it is painful to write (or maintain) the test, then that is a good indication that the abstraction is wrong or not being properly tested. Don't be afraid of deleting tests when they are not useful.
I often find that these unanticipated bugs are often due to incorrect abstractions. To fix it, create the correct abstraction and test it.
It is also simply faster to develop in larger projects than creating the state that would test your unit. For example, you could make a change, manually refresh the page, and debug or write the test and make it pass. You also get the benefit of regression testing.
Note that the narrower your unit, the less likely it will be useful for regression purposes.
I often find that when beginning a project, my units are smaller. As abstractions are built, the nonessential tests are deleted and future tests are built upon abstractions that I care about.
If you are writing bad stateful code that has a lot of bugs and you are not smart enough to figure out how all the states interact, unit tests will help you a lot, but there are many other scenarios where unit testing is useful.
I would not say good code has few unit tests. I say arrogant code has few unit tests. If you write few unit tests, as the size of the codebase grows, you have increasingly less certainty about how any change to the existing codebase will affect other parts. When the codebase is small, this is not a problem. If you are very intelligent, the size of the codebase that you can manage in your head might be quite large. But you are just wasting mental capacity that might have been doing so many more interesting things if you didn't have to remember everything and could trust your unit tests to give you the information you need when you need it.