q This code loops through each field and outputs the cells that contain the names, the types, the constraints, and the comments.
7.2 P REPARING FOR COMMON CONCERNS
Who can argue with code quality? Because unit tests create higher quality, more reliable code, it’s tough to argue against them, but the specter of time and money can cast a shadow on the value of code meant for testing instead of production. Here are some of the more common concerns about unit testing.
7.2.1 Unit tests won’t be maintained
Maintaining production code is difficult enough without having to maintain the sup- porting unit tests. That may be true, but there are ways to ensure that your company’s investment in unit tests is maintained:
• Keep the tests simple to create and maintain. One strategy is to keep your tests close to the code being tested. Another is to use code generation to make build- ing the tests simple.
• Make the test framework visible and easy to run. Ideally it should also leverage your existing development tools, or the test framework tools should be installed as part of the build environment install. No barriers should exist between the intention to test the code and the actual running of the tests and receiving an understandable report.
• Support multiple levels of reporting. You should be able to test the overall system and get back a high-level report telling you what works and where you might run into problems. The user should be able to drill down on issues or rerun tests in specific areas to get more information about where issues are located.
• Make unit testing part of the culture. Ensure that time is allocated for unit test development. Run the unit tests automatically every night with email notification of failures so that everyone knows when and where unit tests are failing.
7.2.2 It’s too hard to make unit tests
This is sometimes rephrased as “Unit tests won’t work on my code.” If you can write the code, tools are out there to test the code. It’s true that some types of code are easier to test than others. You need to analyze how to spend your QA money and balance the importance of the code being tested against the difficulty and expense of testing it.
For all of the code domains (e.g., database access, interface, RPC) presented in this book, effective unit test tools are available both in the public domain or for purchase. If you are willing to spend the money and the time, tools are available that make build- ing tests for your application easier. APIs can be tested through white box unit tests, web interfaces can be tested through robots, and client/server applications can be tested through front-end testing tools, such as those from Segue (www.segue.com).
7.2.3 Unit tests will limit our flexibility
It seems counterintuitive, but unit tests actually increase your flexibility by allowing you to accept more risks in refactoring code. If you have thorough unit tests for your mod- ule, then you can refactor the code any way you please; so long as the unit tests pass, you can be reasonably sure that the module is still running properly.
Working with unit tests is an immensely gratifying experience. If you have not worked with a solid unit test framework before, you are missing out on valuable peace of mind. It will be the end of sleepless nights spent worrying about application sta- bility or reliability.
A CASESTUDY: AUGMENTED C CODE 143
7.2.4 The interface isn’t ready yet
When fully embraced, unit testing inverts the development process. You start by devel- oping the unit tests, and then implement the interfaces to match the unit test cases. These tests should cover both normal and error conditions. Once the tests pass, you can feel confident that the interface is implemented completely.
When you invert the development process to create the unit tests before doing anything else, the question of whether the interfaces are sufficient for tests becomes a non-issue.
7.2.5 Unit tests are not worth the time
To understand the value of unit tests, you have to try using them at least once. I can guarantee that after you have experienced the confidence that comes with writing code with a unit test running as a bug-catching safety net, you’ll never have to be convinced again.
7.2.6 Adding unit tests to a legacy system is painful
Let’s face it: Doing almost anything with legacy code is painful. And that pain is mul- tilayered. First, you have to try to understand the code. Then comes figuring out what changes need to be made. Finally, there is the fear that new changes will break the code. This last part is where unit tests pay off. If you had unit tests in the first place, you wouldn’t be worrying about the ramifications of code changes.
When you are modifying core components of a legacy system, it is worth the time to integrate unit tests before making the changes. If you have thorough unit tests and they pass after the modifications, you can be reasonably satisfied that the system is stable.
7.2.7 Unit tests can only prove the existence of errors
In 1968 Edsger Dijkstra wrote that “Testing can demonstrate the existence of errors, but never their absence.” The idea is that you should be able to mathematically prove the validity of an algorithm and thus prove every possible test case. This is both fascinating and true. If you have algorithmic tests, you may not need unit tests. However, if your system does not have algorithmic tests you should consider using unit tests as a starting point to ensure code quality.
Our case study on unit test generation uses a generator that builds unit tests by parsing the test data directly from a C implementation file.