Why do we care so much about automated tests?

They make us more accurate, faster, and more reliable, and they make our code easier to maintain and extend.

2024-03-23 Michael Harris

Automated tests are instrumental to our development process. They're not new. They aren't unique to us. But they do take discipline to write frequently and correctly. And when done well, they dramatically improve the quality and speed of any dev team.

What is automated testing?

We're writing software. Software is code that runs on computers. Computers execute code quickly and deterministically. We can use this to our advantage to ensure - over and over and over again - that the code we write is working as expected, even after we make significant changes.

How does it work?

  • We work with clients to determine how the software should behave.
  • We translate these expectations into code that the computer can run. So far, all tests will pass because we haven't written any code that actually implements the required behaviors.
  • We write code to implement the required behaviors. Tests start to pass.
  • We refactor the code to make it more maintainable. Tests continue to pass - unless they don't - in which case we know we messed up immediately and can fix it.
  • We add new features. Tests continue to pass - unless they don't - in which case...
  • If a bug is discovered, we write a test that reproduces the bug. Then, we fix the bug. Tests continue to pass. The bug is now reliably fixed forever.
  • etc...

For alternative explanations, check out these 2 and 3 minute YouTube videos:

But why, though?

Let's break down the points mentioned in this article's subtitle:

They make us more accurate

Every programmer has written code that they thought was correct, only to find out later that it wasn't. That's what bugs are.

Automated tests force us to be explicit with our assumptions of how the system should behave. This benefits us on the one hand by simply improving the clarity of our requirements, which often results in rich conversations with clients and stakeholders to discover new things about the system being developed. It benefits on the other hand by catching subtle bugs in the code we write, before it gets released.

The sooner we catch bugs, the easier they are to fix. We call this failing fast, and it's one of the most important techniques to improving software speed and quality.

They make us faster

All software development is iterative. We're always testing, whether it's automated or manual clicking.

Computers are much faster than humans clicking. Computers test the same things every time, whereas humans might forget or skip or do something slightly different.

Did I mention how much faster computers are?

The speed of iterations in software is critical to the speed of delivering the final product. Also, when our tests run fast, we can test more often. Testing more often enables us to test less new code each time, so that when things do break our tests, it's much easier to find the culprit and fix it.

Writing tests takes slightly more time up front, but they rapidly pay for themselves after just a few iterations in speed improvements alone, not even counting the other benefits.

They make us more reliable

If you've been on software projects before that have reached any moderate level of complexity, you've probably experienced what we call the whack-a-bug spiral. This is when, during the course of adding new features to existing software, we inadvertently cause side effects that break other parts of the system. Fix that, and another bug pops up. And so on...

Automated tests help to mitigate this by failing fast.

Over time, with even moderate diligence, we can build up a suite of tests that cover the majority of our codebase. This suite of tests acts as a safety net, catching bugs before they get released.

Finally, when we have automated tests, we also now have the ability to include them in our continuous integration pipeline. This means that every time we make a change to the codebase, we can run all of our tests automatically to ensure that we haven't broken anything. If a test fails, we can't deploy these changes to production. This is a huge benefit to the reliability of our software.

They make our code easier to maintain

When we have a suite of automated tests, we can refactor our code with confidence. Refactoring is the process of changing the structure of our code without changing its behavior. This is important because as we learn more about the problem we're solving, we often find better ways to structure our code.

Without tests, we'd be flying blind and playing our favorite game of whack-a-bug every time we made a change.

They make our code easier to extend

Similar to improving maintainability, when we have a suite of automated tests, we can add new features with confidence. We can be sure that we haven't broken anything that was previously working.

With really good tests in place, we can even make substantial changes with confidence. Rather than manually testing and theorizing over how big changes might impact the system, we can throw the boat in the water and see if it floats.

Everybody should use automated tests

So we do.

We've been on projects on past assignments where automated tests were either non-existent or not taken seriously. The result is always the same: a slow, buggy, unreliable system that's difficult to maintain and extend.

Often the team might be humming along just fine at first, but as the complexity of the system increases, the team's velocity slows to a crawl. The team is constantly putting out fires, and the business is constantly frustrated with the lack of progress.

This happens way more often than it should in our industry.

So we've made a commitment to ourselves and our clients to always write automated tests. We've seen the benefits firsthand, and we're not going back.