|Just another Perl shrine|
Automated testing is one of my favorite parts of the development process. It is also one of the most important in my opinion - on the same level as revision control and documentation.
Developers often comment that automating testing is important, but that it is not really an option for the project they are working on. I am convinced that this is false is almost all cases.
One common reason against testing is that the code in question is too complex for a unit test to verify. The only part of that sentence that I find correct is that the code is too complex. The code in question should likely be refactored into a few objects/functions that are tightly cohesive and loosely coupled. This sort of design is much easier to verify, and it reduces repetition.
Another common assertion is that there isn't enough time before the deadline to write the code AND the test suite. This is only true in cases where you are adding the test suites at the end of the development cycle. Instead they should be developed alongside the code, or even better, before the code.
It's common for developers to run the same block of code many times, manually verifying the debug output each time. Sure, it only takes 45 seconds to verify that way - but it's 45 seconds every time you change the algorithm, and it adds up quickly.
And if you change the algorithm you now need to verify that it behaves correctly in all of the edge cases, as well as in some known problem sets. Whereas if you keep the same set of tests from the previous implementation you can run them after optimization and know instantly whether it still behaves according to specifications.
Developing the tests before the code is implemented is another huge time-saver. How many times have you implemented a large portion of a module before realizing that the way you had planned to use it just isn't feasible, and you now need to change the interface? At this point you need to assume that all of the inner workings need to be verified again.
To avoid some of that pain you should write the test cases before the implementation. This allows you to write the code from the point of view of a user of this module, which often points out flaws in your plan. You can then incrementally develop the module, and modify your tests whenever you discover a new requirement. This also encourages highly cohesive code.
Another benefit of test driven development is that your system grows at a steady and predictable pace, because bugs are detected and fixed early in the cycle instead of at the end... particularly during the optimization period.
And perhaps the most important reason to develop automated testing is to prevent bugs from reappearing. News bugs will irritate clients, but the reappearance of an old bug will infuriate them. To avoid this embarassing situation you should always write a test case that fails because of the bug in question before fixing the bug. Now all you have to do is run your entire test suite before each release, and you should be safe.