I think it depends a lot on the nature of the problem that you're tackling. If you know in advance that your task is to turn input 'A' into output 'B', then I think it makes sense to write some of your tests before writing any of your actual code.
Most of the projects I'm involved with, however, are highly experimental, both in terms of the inputs and outputs that we're dealing with, as well as the ways we interact with the user. Writing tests or even specifications (except in the most generic sense) upfront makes no sense in this case: what we need to do is quickly make some crude stuff, play around with it, and then make slightly less crude stuff. Wash, rinse, and repeat.
After several cycles of this, we know what we actually want to do, and can start buckling down and writing production code. Some of it may or may not be borrowed from the prototyping cycles. In any case, testing becomes CRITICAL at this point.
That's what I use tests to do. Because of the effort of setting up and re-factoring the tests I have a long hard think before I write any code.
I consider it using an API before writing it any code. Doing this forces me to consider how I would actually use it and usually my initial assumptions on how the code should work are wrong.
I usually end up with the correct solution this way. This is of course for small parts of the application. The overall idea may be wrong, but since everything is now in small reusable components its easy to plug and play to get the correct solution.
Probably the same result as rapid iterations, throwing away portions and then building correctly the last time. I wonder which one is more effective or if its dependent on the person.
Most of the projects I'm involved with, however, are highly experimental, both in terms of the inputs and outputs that we're dealing with, as well as the ways we interact with the user. Writing tests or even specifications (except in the most generic sense) upfront makes no sense in this case: what we need to do is quickly make some crude stuff, play around with it, and then make slightly less crude stuff. Wash, rinse, and repeat.
After several cycles of this, we know what we actually want to do, and can start buckling down and writing production code. Some of it may or may not be borrowed from the prototyping cycles. In any case, testing becomes CRITICAL at this point.