The book introduces automated testing, but also discusses how tests can be managed in real teams. One of the main points here is how the same best practices that you use for production code should go into automated tests -- if you use certain object oriented patterns, small methods, SOLID principles, and so on, then these techniques should be used for test code as well.
This leads into the practice of writing maintainable test code: the relationship between engineering and craftsmanship.
Civil engineers may supervise and inspect the building of bridges or buildings, but they spend little time driving rivets, pouring concrete, or stringing suspension cables. Probably the closest to software engineers' total immersion might be the handful of test pilots who are also aeronautical engineers, in that they participate in design, construction, inspection, and verification of the craft they fly.
spyOnfunctionality provides the full range of test-double variations by substituting a test-instrumented recording object for the function being replaced and letting you define how it behaves when invoked.
What I learned most from, though, was the higher-level advice, like "test the error paths":
Many people stop before testing the error handling of their software. Unfortunately, much of the perception of software quality is forged not by whether the software fails, because it eventually will, but by how it handles those failures.
And the following point reinforced the way I work, mixing "spec"-like tests with integration and unit tests:
I prefer to test each defect, at least at the unit level.
Stephen sometimes talks about how most of our programming languages and tools aren't designed specifically to support testing. One idea that runs through the book is about how to design code to be testable, and writing decoupled tests is part of this. Balancing encapsulation with access to internal state for testing is something that I think most of us struggle with.
As we have seen, verification of those internal representations sometimes occurs through interface access. Where null safety is either guaranteed by the representation or ignored by the test, we see code like
A.getB().getC().getD()Despite the blatant violation of the Principle of Least Knowledge, we frequently find code like this-of course we do not write it ourselves!— in tests and production.
Chapter 12, "Use Existing Seams", left an impression on me: it's about the idea of finding places in code that allows you to take control of that code so you can bring it under test. Since reading that chapter I seem to have found more convenient places to grapple Express applications and test them more thoroughly.
Stephen has combined years of experience into a rare, testing-focused book, that relates principles that we use to write well-designed code to the problems inherent in automated testing.