When do you test, how do you test, why do you test? Or even do you test?
The answers to the first two questions are: “all the time,” and “as completely as possible.” The third question has several, longer, answers. And if you answered “No” to the last question, perhaps those answers will be of use to you.
A first, and rather flippant, answer is “so I know when I’m done.” But even this answer has depth. I don’t just mean, “I got all the bugs, so I can quit.” Whether I’m working off a highly detailed spec, or a back-of-the-napkin sketch I did over dinner, the tests I write will reflect exactly what the object’s supposed to do.
In the case of the detailed spec, writing the tests will help to bring my attention closer to the code I’m about to write, setting the boundaries, as it were, of the piece of the project I am immediately concerned with. It starts the coding engine, deep in the recesses of my brain, working on the specific problem the spec is designed to solve. It helps focus my energies on what’s happening right now; in the vernacular, it sets the stage for “flow.”
In the case of the vague sketch, writing tests will do all that, and more. It will start to bring that vague notion into sharper relief, giving it a concreteness that it previously lacked, enabling me to do a better job of bringing it into existence.
But in either case, so long as a failed test remains I know I haven’t finished. And I have a very short-term, easily understood goal: to fix the problem that made it fail. Testing clarifies the issue I have to worry about, I can set all the whole “big picture” thing aside and simply focus on passing the tests in the easiest, cleanest, most efficient way possible.
If no failed tests remain, then I know I’m done.
But that’s not the only reason I test. I test so I can break my code, reduce my elegant solution to a quivering mass of bits. The purpose of every test I write is to break my code, somehow.
If an application can be thought of as a living thing, that grows and interacts with its environment, then the code itself is the skeleton. It gives the application structure, enables it to fulfill its purpose. So why do I want to break It? Because bones, when broken, can heal back to be stronger than they were before. It truly can be said of an application, “that which doesn’t kill me will make me stronger.”
And that’s the goal. If I break my app, and fix it, before you break it, the app you receive will be better for it.
I also test for understanding. This primarily goes for maintenance projects, of code someone else has written, but it also goes for my own code, that I may have written some time ago. Reading the tests will illuminate what the “edge conditions” are, and writing new tests will improve my understanding of the code in front of me. And give me immediate feedback (in terms of the result of the test) on the level of understanding I have.
Finally, I test to remember. In “Soul of a New Machine” Tracy Kidder recounts the story of how the designer of the new hardware in the Eagle tested and verified his design. Once he was satisfied it was complete, he played Adventure on it. This was because once, years before, a user had found a hardware bug that he could only trigger while playing Adventure.
I write tests to capture bugs that have been reported in the wild. Once the test reliably fails, I fix the bug, but leave the test in the suite. This makes sure that no future change made to the code will unwittingly reintroduce that bug. The test has captured knowledge from the past, and will always remember it, even when it’s (temporarily or permanently) slipped my mind.
Code that I have written tests on is clearer to me, it’s stronger (after it passes the tests) and I know that not only am I finished with it, I can be sure it performs according to expectations.
So try it yourself (please!) and see what it does for you. At first, you’ll write some pretty sloppy tests, and you may find yourself debugging tests as often as debugging real code. But you’ll improve, and your tests will become more and more meaningful, more useful. And it won’t be long before you wonder (like I do) how you ever got along all that time without testing.