Accessibility

Table of Contents

Test Driven Development with ColdFusion – Part 2: Designing components for easy testability

What makes components hard to test?

Picture a modern bicycle wheel. The spokes slide through the hub and connect to the rim via threaded nipples. When the rim bends, truing the spokes will straighten it. When a spoke breaks, it is easily fixed. Flat tires are inconvenient but cheaply remedied with minimal effort.

As a system, this wheel comprises many simple components that perform single, specific functions. Because this wheel is designed for maintenance, the components are made to be easy to replace. Now, imagine if the spokes were welded to the hub, and the tire a solid hunk of rounded rubber chemically fused to the rim. If constructed this way, wheels would be virtually unmaintainable because their components couldn't be swapped out for new ones when they failed.

In modern software, the code you write is rarely self-contained. Often, it interacts with external systems and uses components that you or others have written to do its work. These external systems and components are often known as dependencies, and these dependencies make your components difficult to test.

Dependencies include, but are not limited to:

  • Databases
  • Network services (web services, REST, email, SMS, and so on)
  • File systems
  • Clock time (for time-sensitive operations)
  • Other components whose behavior is undesirable or difficult to control at time of test

In our experience, most nontrivial applications require such conditions. Furthermore, since these dependencies are precisely what lead to difficulty constructing meaningful tests, this critical functionality often goes untested. This results in anemic tests that exercise less critical functionality, thereby reducing test coverage and simultaneously creating the conditions for a false sense of security. People start to think, "I have a unit test for component X, and the tests are all Green. Component X is tested. My work is done here!"

Eventually, as team members and managers realize that the existing tests aren't helping much—and in fact may be hindering the effort due to the false sense of security they impart—the case for spending time on programmatic testing begins to fall apart. As the return on investment for unit testing approaches zero, the encouragement for testing dwindles, and you start writing fewer tests, and eventually no tests.

This feedback loop demoralizes developers and managers alike.

You can turn this around, and through the use of some simple strategies and freely available tools take testing to a place where you achieve thorough coverage, confidence in your tests, and better object-oriented code. By applying these strategies, designing for easy testability can lead to:

  • Smaller, more focused functions
  • Isolation of external dependencies from application logic
  • Increased opportunities for code reuse
  • Components that are easier to debug and maintain