Software testing is so burdened with the weight of varying dogma and competing ideologies that it's very easy to forget the reasons why we actually bother writing tests at all.

For me, as an engineer I care about a pleasant development experience and I care about working code. The former is hard to quantify but it normally comes down to the following attributes:

  • Being able to understand a codebase
  • Being able to refactor without fear
  • Being able to commit without fear

For non-engineering stakeholders the things valued usually come down to:

  • Features that work
  • Speedy development

A truth that eludes many is that when the engineering concerns are fulfilled they coincide with the fulfillment of the business concerns. If I have a well-tested codebase then I can easily add new features without worrying that I'm breaking some unrelated thing. So, from this, we get both a working feature and speedy development.

And so it seems plain as day that tests result in business needs being fulfilled, but it is not always clear. The benefits at any particular time are often deferred. It takes a broad perspective to see the value in something when it will not be immediately realised.

If I write a well-tested module now, I may get a fuzzy feeling inside, but its benefit beyond that will only surface in four or five months' time when the next developer has to come along and add or change something. To fully appreciate the virtue and necessity of testing one has to look beyond the current hardships and sprints and onto the impending cesspit of doom potentially created by untested code.

The beauty of tests is that they have such an abundance of benefits:

  • Code via repeatable and deterministic specs
    (the tests are static and predictable “users”)
  • Design better APIs
    (the tests are the first consumer of your API)
  • Confirm and clarify your intent
  • Provide a way for those new to the codebase to fully understand it
    (documenting both the broad and the granular)
  • Protect features and modules from future changes
    (to fight regressions & the fear of them)
  • Discover the symptoms and causes of bugs

So, go forth and test!

But beware: Tests won’t be the redeeming grace of poor architecture; they complement a well written codebase. Their effectiveness can suffer when they’re too granular, too implementation-dependent, too broad or too vague. They're definitely not a silver bullet.