Reasons to Write Unit Tests (Besides Making Sure Your Code Works)

Anish Krishnan
4 min readApr 9, 2021

As a software engineer, one of the most important concepts we’re taught — and often neglect — is unit testing. We’re told to unit test our code, but many of us (a) forget to do so, (b) neglect doing so because we don’t see their value, and/or (c) eschew unit tests in favor of integration and end-to-end tests. Sometimes a deadline is pushed forward and we simply don’t have the time. On other occasions we might just be lazy. But while many of my philosophies within software development have changed over time, I have remained steadfast on this principle: Code without unit tests is incomplete code.

To be clear, we can’t always write unit tests (see my point above about deadlines). In those cases, it’s a developer’s responsibility to make note of that — preferably within an issue-tracking software like Jira and not in a TODO code comment — so that the team can return to it later. But the fact is that unit tests should be considered a key part of any deliverable. Here are just a few reasons why.

  1. They help us understand our code. If this sounds silly, ask yourself if you’ve ever injected defects into a system that could have been easily avoided. Whether you’ve forgotten to negate a conditional statement, convert one data type into another, or properly format incoming data, careless mistakes are inevitable in the development process. Writing modularized unit tests forces us to reread our code line by line, verifying that calls to services were made with the correct arguments in the right order, that a function returned what we expected, that the sequences of events occurred in the right order. Even if you yourself never make mistakes, maintaining a practice of writing unit tests will help your team members who do. What constitutes a good unit test is a topic for another piece, but the general rule is simple: stick to the unit of code (typically a method/function) you’re testing. Calls to any other methods should generally be mocked out.
  2. They enforce good coding principles. Unit tests are a great way to uncover code smells. They force us to address messy code and anti-patterns. Why? Because the more unnecessarily complex a component is, the harder it will be to unit test. If you find yourself testing the same logic over and over, there’s a chance that said logic could be refactored into a helper method instead. If you notice that you have to write unit tests for eight different logical permutations due to deeply nested “if” statements, then it’s time to figure out a better way to handle those conditionals.
  3. They keep track of changes. Sometimes our feature branches grow larger than we had initially anticipated, and that’s okay. The important thing is that if we’ve changed a lot of existing code, we should expect tests to break. (If you’re practicing TDD, you’d change the tests first, but that’s a separate discussion.) Assuming we have a comprehensive unit test suite, that’s a good thing — tests breaking in the right way should be expected behavior, confirming that yes, we made changes, and that those changes affected the logic in expected ways. As the number of commits we’ve made to a branch increases, so too does the value of knowing about all of the changes we’ve made to the codebase. Sure, we can see those changes in a git diff/on GitHub, but seeing tests break in real time gives us specific information on what exactly we’ve been doing to our code, and more importantly, whether we’ve done it correctly.
  4. They communicate what our code is trying to accomplish. Unless we’re working on a personal project, chances are others are going to see — and hopefully review — our code. Unit tests can serve as a valuable form of documentation. With every test case, we inform our team members of what a method should do in a particular set of circumstances. If we’re reviewing others’ code, reading their tests can help us understand what they’re trying to accomplish, as well as give us assurance that they’ve written their code accurately (and with good coding principles!). Despite whatever stereotypes may persist, software engineering is a collaborative activity. Communication is vital, and unit tests are a form of communication through code.

This is by no means a comprehensive list, but rather just a few important reasons to maintain a unit testing mindset. It’s a solid habit to get into, and while it may seem like an inconvenience at first, it shapes us into better engineers with time. Whether it’s being forced to rethink a lengthy method, letting our team members know the logical nuances of our code, or just making sure we haven’t made any careless mistakes, it’s a practice we should all adopt — no matter how mundane it may seem in the beginning.

--

--

Anish Krishnan

Consultant, software engineer, cloud architect, news junkie, and arguably musician. https://linktr.ee/aykrishnan