This reference presents, in detail, an effective, step-by-step, cost-effective approach to software testing that is based on common practice--with improvements inspired by academic testing research and practial experience. The approach is designed to be gradually adoptable, so that it does not disrupt current work, and it scales down gracefully under schedule pressure. Outlines a systematic process/strategy of software testing that incorporates test design, test implementation, and measurements of test quality. Explains solid testing techniques in detail and shows how to apply them to testing tasks. Answers such questions as: How do I design tests? What are common tester errors, and how do I avoid them? How do I implement tests? How do I know how good my tests are? How do I know when I've tested enough? Features unique coverge of testing bug fixes and other changes. For software developers testing their own code or designs; indepdendent testers testing someone else's code; and testers or developers testing bug fixes and other maintenance changes.
Contents
Preface An Overview of Software Testing
PART 1: THE BASIC TECHNIQUES 1. The Specification 2. Introduction to the SREADHEX Example 3. Building the Test Requirement Checklist 4. Test Specifications 5. Test Drivers and Suite Drivers 6. Inspecting Code with the Question Catalog 7. Using Coverage to Test the Test Suite 8. Cleaning Up 9. Miscellaneous Tips
PART 2: ADOPTING SUBSYSTEM TESTING 10. Getting Going 11. Getting Good
PART 3: SUBSYSTEM TESTING IN PRACTICE 12. Using More Typical Specifications (including none at all) 13. Working with Large Subsystems 14. Testing Bug Fixes and other Maintenance Changes 15. Testing under Schedule Pressure
PART 4: EXAMPLES AND EXTENSIONS 16. Syntax Testing 17. A Second Complete Example: MAX 18. Testing Consistency Relationships 19. State Machines and Statecharts 20. Testing Subsystems that Use Reusable Software 21. Testing Object-Based Software 22. Object-Oriented Software 1: Inheritance 23. An Example of Testing Derived Classes 24. Object-Oriented Software 2: Dynamic Binding
PART 5: MULTIPLYING TEST REQUIREMENTS 25. Simpler Test Requirement Multiplication 26. Multiplying Operation Test Requirements
PART 6: APPENDICES A. Test Requirement Catalog (Student Version) B. Test Requirement Catalog C. POSIX-Specific Test Requirement catalog (Simple) D. Question Catalog for Code Inspections E. Requirements for Complex Booleans Catalog F. Checklists for Test Writing
Brian Marick first learned to program in 1976, using the Tutor language. He has since done real programming in C, Common Lisp, Java, Ruby, Clojure, Elixir, and Elm. Much of his career, though, has been spent consulting, first on software testing, then–after he lucked into being one of the authors of the Manifesto for Agile Software Development–on testing and programming on Agile teams. He's written four books, three of which you can still buy: The Craft of Software Testing (horribly out of date), Everyday Scripting with Ruby, and Functional Programming for the Object-Oriented Programmer (almost entirely about dynamically-typed functional languages). He's currently trying to make a modest living writing webapps for schools of veterinary medicine, deliberately using advanced languages and techniques so that he has real-world examples to use in books, training, and consulting.
I recently skimmed over this book but found it very heavy going. Written before Marick started pioneering an Agile approach to testing, it follows a programming by contract approach, in which tests are built from clues gleaned from code specifications, that is to say from carefully analyzing preconditions, postconditions, class invariants and constraints on related clusters of classes. Preconditions and postconditions include sections on exception handling. Code coverage is studied afterwards, in order to identify possible weakness in test suites developed from specification clues. Marick also shows how clues and test specifications can be derived from syntactical descriptions of valid input and from state machines and statecharts.
Surprisingly for a book purportedly on subsystem testing, the examples are all small. Two specific chapter-long examples are worked on in excruciating detail: one, SREADHEX, a C routine that picks out hexadecimal digits from a character string and packs them, two per byte, into a byte string and the other a method to find a substring matching. Both are really examples of unit, rather than subsystem testing. Most of the other examples are at relatively simple data structure level (hash tables, strings, collections, arrays, streams, trees, pointers). Reading the SREADHEX reminded me of how needlessly complicated and ticky some of the C routines of the time were; however it must be noted that in spite of some examples to the contrary, the book is more C++ than C based.
There is no use of test tools -this is before JUnit, and if I remember correctly still a time in which proprietary tools dominated the testing landscape.
In short, an interesting book for its time which I would would not recommend to current students, even though most of its ideas are still sound.
A warning: This book was published in 1995, 14 years before the Manifesto for Software Craftmanship (http://manifesto.softwarecraftsmanshi...), and except for its painstaking devotion to detail, does not really embody the specific principles of the manifesto.