Do Unit Tests Find Bugs?
I've been writing software for over 20 years and don't believe unit tests find bugs.
Yet, I wouldn't want to work in a code base without unit tests.
Why unit tests don't find bugs?
To understand why unit tests don't find bugs, we can look at how they are created. Here are the three main ways to handle unit tests:
developers write the tests along with writing the code
Test Driven Development (TDD)
unit tests are considered a waste of time, so they don't exist
When the same software developer writes unit tests and code simultaneously, the tests tend to reflect closely what the code does. Both tests and code follow the same logic, stemming from the same understanding of the problem. As a result, the tests won't find major implementation issues. If they find small typos or bugs, it's usually only by chance.
Test-driven development calls for writing unit tests before implementing product changes. Because no product code exists, the unit tests are expected to fail initially or even not compile. The goal is to write product code to make the tests pass. In TDD, new unit tests are added mostly to drive the implementation of new scenarios. An unsupported scenario could be considered a bug, but it's far-fetched. As a result, TDD rarely finds existing bugs.
If unit tests don't exist, they cannot find any bugs.
If unit tests don't find bugs, why do we write them?
While unit tests are not great at finding bugs, they are extremely effective at preventing new ones. Unit tests pin the program's behavior. Any change that visibly modifies this behavior should make the tests fail. The developer whose changes caused the failures should examine them and either fix the tests—if the change in the behavior was intentional—or fix the code. Many test failures indicate assumptions that the developer unknowingly broke. Without tests, they would turn into customer-impacting bugs.
Other important advantages of unit tests include:
Documentation - comprehensive unit tests can serve as product specification
More modular and maintainable code - writing unit tests for tightly coupled code is difficult. Unit tests drive writing more modular and loosely coupled code because it is much easier to test.
Automated testing - unit tests are much faster to run and more comprehensive than testing changes manually.
If unit tests don't find bugs, what does?
There are many ways to find bugs in the code. Integration testing, fuzz testing, and stress testing are just some examples. However, the three below are my favorite because they require little to no additional effort from the developers:
Exploratory testing: Try using the product you're working on. See what happens if you combine a few features or try less common scenarios.
Code reviews: One weakness of unit tests is that they are implemented with the same perspective as the code. Code reviews offer the ability to look at the change from a different angle, which often leads to discovering issues.
Paying attention: Whenever you code, debug, or troubleshoot an issue, have your eyes open. Many bugs are hiding in plain sight. Carefully reading error messages, logs, or stack traces can lead to identifying serious problems.
If you found this useful, please share it with a friend and consider subscribing if you haven’t already.
Thanks for reading!
-Pawel