You are previewing Quality Code: Software Testing Principles, Practices, and Patterns.
O'Reilly logo
Quality Code: Software Testing Principles, Practices, and Patterns

Book Description

Test-driven, test-first, and test-early development practices are helping thousands of software development organizations improve their software. Now, in Quality Code: Software Testing Principles, Practices, and Patterns, Stephen Vance builds on all that’s been learned about test-driven development, helping you achieve unprecedented levels of first-time quality. Using real-world code examples, this guide introduces patterns, principles, and more than two dozen detailed techniques for testing any software system more fully, effectively, and painlessly. Vance presents a conceptual framework to help you focus your efforts and design recommendations for improving testability across the software lifecycle, and also provides hands-on guidance to simplify testing of the full spectrum of code constructs. You’ll learn how to choose the best testing techniques for every situation, from the most common scenarios to threading. Two complete case studies put it all together, walking you through testing a brand-new Java application and an untested “legacy” JavaScript jQuery plugin. Whether you’re developing cutting-edge code for a new start-up, or maintaining an unruly old system, this guide will help you deliver exactly what you need: quality code.

• Simplify unit testing of all your code—and improve integration and system testing

• Delineate intent and implementation to promote more reliable and scalable testing

• Overcome confusion and misunderstandings about the mechanics of writing tests

• Test “side effects,” behavioral characteristics, and contextual constraints

• Understand subtle interactions between design and testability—and make them work for, not against, you

• Discover core principles that guide your key testing decisions

• Explore testing getters/setters, string handling, encapsulation, override variations, visibility, singleton patterns, error conditions, and more

• Reproduce and test complex race conditions deterministically

Table of Contents

  1. Cover Page
  2. About This eBook
  3. Title Page
  4. Copyright Page
  5. Dedication Page
  6. Contents
  7. Preface
    1. What Is This Book About?
    2. What Are the Goals of This Book?
    3. Who Should Read This Book?
    4. What Background Do You Need?
    5. What Is in This Book?
    6. Those Who Came Before
  8. Acknowledgments
  9. About the Author
  10. Part I: Principles and Practices of Testing
    1. Chapter 1. Engineering, Craftsmanship, and First-Time Quality
      1. Engineering and Craftsmanship
      2. The Role of Craftsmanship in First-Time Quality
      3. Practices Supporting Software Craftsmanship
        1. Testing
      4. Unit Testing under Code Checker Constraints
      5. Unit Testing for Coverage
    2. Chapter 2. Intent of Code
      1. Where Did I Put That Intent?
      2. Separating Intent from Implementation
      3. A Simple Example That Makes You Think
    3. Chapter 3. Where Do I Start?
      1. An Approach to Testing
        1. Understand Your Scope
        2. A Conceptual Framework for Testing
        3. State and Behavioral Testing
        4. To Test or Not to Test
      2. The Recipe
        1. Test the “Happy Path”
        2. Test the Alternate Paths
        3. Test the Error Paths
        4. Test the Data Permutations
        5. Test the Defects
    4. Chapter 4. Design and Testability
      1. A Word on Design Paradigms
      2. Encapsulation and Observability
        1. Representational Encapsulation
        2. Behavioral Encapsulation
        3. Shades of Testing
        4. Encapsulation, Observability, and Testability
      3. Coupling and Testability
    5. Chapter 5. Testing Principles
      1. Craft Your Tests Well
        1. Couple Inputs to Outputs
        2. Use a Naming Convention
      2. Avoid Test Code in Production
      3. Verify Intent over Implementation
      4. Minimize Coupling
      5. Prefer Minimal, Fresh, Transient Fixtures
      6. Use Available Facilities
      7. Prefer Complete over Partial Verification
      8. Write Small Tests
      9. Separate Your Concerns
      10. Use Unique Values
      11. Keep It Simple: Remove Code
      12. Don’t Test the Framework
        1. Don’t Test Generated Code
      13. Sometimes Test the Framework
  11. Part II: Testing and Testability Patterns
    1. Chapter 6. The Basics
      1. Bootstrapping Constructors
      2. Testing Simple Getters and Setters
      3. Share Constants
      4. Locally Redefine
      5. Temporarily Replace
      6. Encapsulate and Override
      7. Adjust Visibility
      8. Verification by Injection
    2. Chapter 7. String Handling
      1. Verification by Containment
      2. Verification by Pattern
      3. Exact Verification by Value
      4. Exact Verification with Formatted Results
    3. Chapter 8. Encapsulation and Override Variations
      1. Data Injection
      2. Encapsulate Loop Conditions
      3. Error Injection
      4. Replace Collaborators
      5. Use Existing No-Op Classes
    4. Chapter 9. Adjusting Visibility
      1. Packaging Tests with Code
      2. Break It Down
      3. Changing Access Levels
      4. Test-Only Interfaces
      5. Naming the Unnamed
      6. Becoming friend-ly
      7. Coerced Access via Reflection
      8. Declarative Scope Changing
    5. Chapter 10. Interlude: Revisiting Intent
      1. Testing the Singleton Pattern
      2. Singleton Intent
      3. The Testing Strategy
        1. Testing the Singleton Nature
        2. Testing the Class Purpose
      4. Discerning Intent
    6. Chapter 11. Error Condition Verification
      1. Check the Return Value
      2. Verify the Exception Type
      3. Verify the Exception Message
      4. Verify the Exception Payload
      5. Verify the Exception Instance
      6. Thoughts on Exception Design
    7. Chapter 12. Use Existing Seams
      1. Direct Calls
        1. Interfaces
        2. Implementations
      2. Dependency Injection
      3. Callbacks, Observers, Listeners, and Notifiers
      4. Registries
      5. Factories
      6. Logging and Other Facilities of Last Resort
    8. Chapter 13. Parallelism
      1. A Brief Introduction to Threads and Race Conditions
        1. Some History
        2. Race Conditions
        3. Deadlocks
      2. A Strategy for Race Condition Reproduction
      3. Test the Thread Task Directly
      4. Synchronize through Common Lock
      5. Synchronize through Injection
        1. Example: Injecting Synchronization through Logging
      6. Use Supervisory Control
      7. Statistical Verification
      8. Debugger APIs
  12. Part III: Worked Examples
    1. Chapter 14. Test-Driven Java
      1. Bootstrapping
      2. First Functionality
      3. Cutting the Cord
      4. Moving to Multiples
      5. Ghost Protocol
        1. Dead End
        2. Spy Craft
      6. Exercising Options
      7. Moving Downstream
      8. Retrospective
    2. Chapter 15. Legacy JavaScript
      1. Getting Started
      2. DOMination
      3. On Toothpaste and Testing
      4. Scaling Up
      5. Software Archeology
      6. Retrospective
  13. Bibliography
  14. Index