I hear this all the time. At my workplace, 18 months ago I and some folks suggested that QA should focus on automating as much of their work as possible. The reason they didn’t – while they understood that it would in the long run reduce their load, they were too busy testing the current iteration to set up automation. 18 months later, they still aren’t testing in an automated fashion and the reason is the same. If they had bit the bullet back then, they’d be an order of magnitude more productive. If they bite the bullet today, the same thing will happen for the future.
The flip-side of this is from the developer end, with “we’re too busy building and releasing the product to test it” or “too busy writing the code to write unit tests”. I think this attitude is horse puckey. My friend and boss Darin points to an article that challenges this notion. Both of these folks are on the money – unit testing is not an optional, aftermarket goody to strap on if there is time left over at the end of development. It is how you know that you delivered what you were supposed to. The quote from the second link says it all and very succinctly:
If you’ve managed to build a system that does the job but is too hard to test, then your system works by coincidence.
When I saw the bugs that were prevented by the most rudimentary unit testing, I became a convert to Test Driven Development instantly. I remain skeptical about most of XP, but this part I have fully bought.
Having a full suite of unit tests (or even an incomplete one) provides the structure to allow a developer more confidence. “Did this change just cause a regression in the code? Well, at least all the unit tests pass.” The notion that we don’t have time to add unit tests is ridiculous. Here’s my strategy for unit testing even large bodies of legacy code without any prior unit tests.
- Take the time and install the frameworks if not there – JUnit, Ant, etc. Lay out the test directories and enable unit tests to be run (if none of this exists.)
- For any bug that is filed, before I touch the code I write a unit test that will catch the current issue and fail on it. I verify the test is indeed failing, and once it does, I fix the issue (as defined by the unit test passing.)
- For any existing code I touch, I first verify the method is covered by a unit test and that the unit test is passing. I cannot be done with the method if the unit test fails, I must return it to passing as a criterion for finishing.
- For any new methods introduced I go by the philosophy of TDD – first write a unit test and a shell method and then develop until the method passes.
It is astonishing how little time it takes to do all of the above. Most unit tests take under three minutes to write. One with a lot of setup, or with a recurring setup that you have to do for the first time might be a little longer. However the overall effort is miniscule compared to the effort of development. Without fail by taking the extra time to write the unit tests, the overall time even including that is shorter than if I wrote none. The code is higher quality, is done faster, and now the library of tests that can be executed by anyone (including the build system) has been expanded. It is truly wins all the way around. Don’t let anyone tell you there isn’t time to do this. If time is that tight, then there isn’t time to not do this.