Chapter 1: Developer Testing
Explains that developers are engaged in a lot of testing activities and that they verify that their programs work, regardless of whether they call it testing or not. Developer testing is defined here.
Chapter 2: Testing Objectives, Styles, and Roles
Describes different approaches to testing. The difference between testing to critique and testing to support is explained. The second half of the chapter is dedicated to describing traditional testing, agile testing, and different versions of behavior-driven development. Developer testing is placed on this map in the category of supporting testing that thrives in an agile context.
Chapter 3: The Testing Vocabulary
This chapter can be seen as one big glossary. It explains the terms used in the testing community and presents some commonly used models like the matrix of test levels and test types and the agile testing quadrants. All terms are explained from a developer’s point of view, and ambiguities and different interpretations of some of them are acknowledged rather than resolved.
Chapter 4: Testability from a Developer’s Perspective
Why should the developer care about testability? Here the case for testable software and its benefits is made. The quality attribute testability is broken down into observability, controllability, and smallness and explained further.
Chapter 5: Programming by Contract
This chapter explains the benefits of keeping programming by contract in mind when developing, regardless of whether tests are being written or not. This technique formalizes responsibilities between calling code and called code, which is an important aspect of writing testable software. It also introduces the concept of assertions, which reside at the core of all testing frameworks.
Chapter 6: Drivers of Testability
Some constructs in code have great impact on testability. Therefore, being able to recognize and name them is critical. This chapter explains direct and indirect input/output, state, temporal coupling, and domain-to-range ratio.
Code samples (Groovy)
Chapter 7: Unit Testing
This chapter starts by describing the fundamentals of xUnit-based testing frameworks. However, it soon moves on to more advanced topics like structuring and naming tests, proper use of assertions, constraint-based assertions, and some other technicalities of unit testing.
Chapter 8: Specification-based Testing Techniques
Here the testing domain is prevalent. Fundamental testing techniques are explained from the point of view of the developer. Knowing them is essential to being able to answer the question: “How many tests do I need to write?”
Code samples (Java)
Chapter 9: Dependencies
Dependencies between classes, components, layers, or tiers all affect testability in different ways. This chapter is dedicated to explaining the different kinds and how to deal with them.
Chapter 10: Data-driven and Combinatorial Testing
This chapter explains how to handle cases where seemingly many similar-looking tests are needed. It introduces parameterized tests and theories, which both solve this problem. It also explains generative testing, which is about taking test parameterization even further. Finally, it describes techniques used by testers to deal with combinatorial explosions of test cases.
Chapter 11: Almost Unit Tests
This book relies on a definition of unit tests that disqualifies some tests that look and run almost as fast as unit tests from actually being called by that name. To emphasize the distinction, they’re called “fast medium tests”. They typically involve setting up a lightweight server of some kind, like a servlet container, mail server, or in-memory database. Such tests are described in this chapter.
Chapter 12: Test Doubles
This chapter introduces typical test doubles like stubs, mocks, fakes, and dummies, but without using any mocking frameworks. The point is to understand test doubles without having to learn yet another framework. This chapter also describes the difference between state-based and interaction-based testing.
Chapter 13: Mocking Frameworks
Here it gets very practical, as the mocking frameworks Moq, Mockito, and the test double facilities of Spock are used to create test doubles for different needs and situations—especially stubs and mocks. This chapter also includes pitfalls and antipatterns related to the use of mocking frameworks.
Chapter 14: Test-driven Development—Classic Style
Here, classic test-driven development is introduced through a longer example. The example is used to illustrate the various details of the technique, such as the order in which to write tests and strategies for making them pass.
Code samples (Groovy)
Chapter 15: Test-driven Development—Mockist Style
There’s more than one way to do test-driven development. In this chapter, an alternative way is described. It’s applicable in cases where test driving the design of the system is more important than test driving the implementation of a single class or component.
Chapter 16: Duplication
This chapter explains why code duplication is bad for testability, but sometimes a necessary evil to achieve independence and throughput. Two main categories of duplication are introduced and dissected: mechanical duplication and duplication of knowledge.
Chapter 17: Working with Test Code
This chapter contains suggestions on what to do before resorting to comments in test code and when to delete tests.
Code samples (Java)
Chapter 18: Beyond Unit Testing
Unit testing is the foundation of developer testing, but it’s just one piece of the puzzle. Software systems of today are often complex and require testing at various levels of abstraction and granularity. This is where integration, system, and end-to-end tests come in. This chapter introduces such tests through a series of examples and discusses their characteristics.
Chapter 19: Test Ideas and Heuristics
This final chapter, on the border of being an appendix, summarizes various test heuristics and ideas from the book.