Chris EK, on life as a continually learning software engineer.

Notes on Cost-Effective Testing (POODR: Chapter 9)

I am working my way through programming-related reading, currently with Sandi Metz’s “Practical Object-Oriented Design in Ruby”. Click here for more posts about POODR.

I’ve written about testing previously, but Sandi Metz, in the last chapter of POODR, lends some valuable insights to testing, specifically about writing cost-effective tests with an emphasis on changeable code. In this post, I simply reference some of her comments on testing that I found most helpful.

Why Test?

Metz starts by describing, “Writing changeable code is an art whose practice relies on three different skills” (191). These three skills, as she sees them, are:

  • Understanding object-oriented design
  • Refactoring code
  • Writing high-value tests

What if the tests are costly themselves?

“The true purpose of testing, just like the true purpose of design, is to reduce costs. If writing, maintaining, and running tests consumes more time than would otherwise be needed to fix bugs, write documentation, and design applications tests are clearly not worth writing and no rational person would argue otherwise” (192).

“The solution to the problem of costly tests, however, is not to stop testing but instead to get better at it. Getting good value from tests requires clarity of intention and knowing what, when, and how to test” (192).

Benefits of Testing

  • Finding Bugs [and finding them early] – “Fixing bugs early always lowers costs” (193).
  • Supplying Documentation – “Tests provide the only reliable documentation of design…long after paper documents become obsolete and human memory fails” (193).
  • Deferring Design Decisions – “Tests allow you to safely defer design decisions…when you are aware of just one concrete case in the present but you fully expect new cases to arrive in the near future” (193).
  • Supporting Abstractions – “There is a level of design abstraction where it is almost impossible to safely make any change unless the code has tests” (194).
  • Exposing Design Flaws – “Tests are the canary in the coal mine; when the design is bad, testing is hard” (194).

Know what to test

“Most programmers write too many tests…The safest way to [write fewer tests] is to test everything just once and in the proper place” (194).

Know when to test

“You should write tests first, whenever it makes sense to do so…Be warned, however, that writing tests first is no substitute for and does not guarantee a well-designed application” (197).

Know how to test

“There are many good reasons to stay within the testing mainstream [with frameworks like MiniTest and RSpec]…Both [TDD and BDD] are completely acceptable. Each has costs and benefits” (199).

In conclusion

Tests are indispensable. Well-designed applications are highly abstract and under constant pressure to evolve; without tests these applications can neither be understood nor safely changed. The best tests are loosely coupled to the underlying code and test everything once and in the proper place. They add value without increasing costs.

A well-designed application with a carefully crafted test suite is a joy to behold and a pleasure to extend. It can adapt to every new circumstance and meet any unexpected need.