The importance of unit testing, or how bugs found in time will save you money
Unit testing still causes controversy among developers and product managers. There are both opponents and supporters of this kind of testing. In this article, I’ll highlight the main advantages of unit testing.
What are unit tests, why unit testing is important, and how it they help developers and business owners? For the answers to these questions and more, read on.
Let’s start with the definition: Unit testing is a software testing method where “units”—the individual components of software—are tested. Developers write unit tests for their code to make sure that the code works correctly. This helps to detect and protect against bugs in the future.
Sometimes developers write unit tests first, then write the code. This approach is also known as test-driven development (TDD). In TDD, requirements are turned into specific test cases, then the software is improved to pass the new tests. In this approach, no code is added that hasn’t been proven to meet defined requirements. Unit testing is similar, in that it allows developers to modify code without affecting the functionality of other units or the product, as a whole.
Unit tests are usually written in the form of functions and check the value and behavior of these functions in various scenarios. For example, let’s imagine a function for the division of two numbers: the developer decides to follow the TDD approach, first writing a test with the input of values ‘4’ and ‘2’ (4 divided by 2) with ‘2’ expected as the result. Another example: when the divisor is zero, we don’t expect that the function will produce a value—we expect that it will generate an exception. We can expect that the function will notify some component about an attempt to divide by zero. Thus, we test two cases:
- In an invalid situation, the function will notify us that we are doing something wrong (an exceptional situation)
- The function will identify this invalid situation and log it
Eight Advantages of Unit Testing
Some developers underestimate the importance of writing unit tests. What follows are five benefits of unit testing that you may want to consider before forming your own opinion.
Any bugs are found easily and quicker
Code covered with tests is more reliable than the code without. If a future change breaks something in the code, developers will be able to identify the root of the problem right away rather than coming through an unwieldy codebase to find the issue.
Best practices suggest that developers first run all unit tests or a group of tests locally to make sure any coding changes don’t disrupt the existing code. However, consider the human factor: A developer might forget to run unit tests after making changes and submit potentially non-working code to a common branch. To avoid this, many companies apply a continuous development approach. Tools for continuous integration are used for this, allowing developers to run unit tests automatically. Thus, any unwanted changes in the code will be detected by a cold, logical machine.
The speed of detecting non-working code depends on the tools used for continuous integration. Tests can be set to run either a one-time check at a certain time interval or can be run immediately in real-time to review changes.
In short, unit tests help developers detect problems immediately, then fix them quickly. With fewer resources spent finding bugs, teams can move on to the next phase of a project.
Unit testing saves time and money
In his book, “Code Complete,” Steve McConnell shares a table with bugs and the cost of fixing them at different stages of the product lifecycle. The table shows that the earlier a defect is detected, the lower the cost of its correction.
When unit tests are written, many bugs are found at the software construction stage, which prevents the transition of these bugs to the following stages, including after the release of the product. This saves the costs of fixing the bugs later in the development lifecycle and also brings benefits to end-users, who don’t have to deal with a buggy product. Also, you will greatly benefit from improved test time estimation, saving lots of time and resources.
Unit testing is an Integral part of extreme programming
Unit tests are a prerequisite for the Extreme Programming methodology. Extreme programming is essentially a “test-everything-that-can-possibly-break” strategy. Writing unit tests with this methodology makes development and code refactoring simpler, integration easier, and creates living documentation. Which brings us to our next point…
Unit testing provides documentation
Unit tests are a kind of living documentation of the product. To learn what functionality is provided by one module or another, developers can refer to unit tests to get a basic picture of the logic of the module and the system as a whole. Unit test cases represent indicators that carry information about appropriate or inappropriate use of a software component. Thus, these cases provide the perfect documentation for these indicators.
R2: Reusable and Reliable
Within unit tests environments, the individual modules of a product become isolated from one another and have their own area of responsibility. That means that the code is more reliable—it’s been tested in a contained environment—and therefore, reusable. Reusable code is a win-win for all: It’s clean, efficient, and consistent. All of this is accelerated with unit testing.
Unit testing helps gauge performance
Wouldn’t it be amazing if you could find out the possible breaking points of your software before it goes into production and users spot them on their own? Unit tests can provide such an opportunity, and can prevent the unnecessary effort of searching for solutions to non-existent issues. For instance, if you work on a hashed list, you may face a need to check how it will perform if the list grows. The rate of growth is unknown. What you will likely do from here is apply unit tests to try out scenarios of varying levels of probability — from highly probable to absurd. If you are already sure that the number of items in the hashed list won’t surpass 10,000 under any circumstances, at 100,000 you are all set and can stop at this point. You have proven your software capacity is good enough, and there’s no need to spend more time testing.
Unit testing improves code coverage
Okay, so software unit testing is great, but how much test coverage is necessary? American software engineer Robert C. Martin, also known as Uncle Bob, argues that the goal of test coverage should be that 100 percent of the code is covered. Opinions among developers on this issue differ: some support a complete code coverage policy, while others consider this practice redundant — a topic too lengthily for the purposes of this article. In any case, when writing unit tests, you can use many tools that determine the total percentage of the coverage of a project, separate module, or function. These tools are also able to graphically display the code sections covered by tests and indicate the sections in the code for which it makes most sense to write unit tests.
It’s very useful to know at the active code writing stage if a particular line will ever be executed or you if can painlessly remove it. If you have valid unit tests, you can have coverage metrics on hand right away, and decide whether a code line is ever relevant. If it’s not, consider expanding your code coverage with one more test. If your test suite already accounts for all possible scenarios, eliminate the unnecessary code. However, the need for more tests is a sign of increasing cyclomatic complexity.
Unit testing reduces code complexity
Cyclomatic complexity is a quantitative measure you can use to understand exactly how complex the program and its code are. The more paths are implied in a single code block, the higher the complexity. Namely, when there’s no control flow statement in the source code, the complexity rate stands at one, and with “if” statements it gradually rises to two or higher. As you can imagine, this is where achieving perfect unit-test coverage becomes a difficult task. The more conditional statements the code has, the more complex the code block is.
Once the creation of unit tests becomes cumbersome, it signals that the code might be overcomplicated too. But without unit tests objectively answering the question of whether your code works or not, all you have is your own assumption. With unit tests, you have concrete proof.
Unit testing results in quality software
All of the factors listed above are interconnected and imply that unit testing undeniably contributes to improving your software. Unit testing may seem like a tedious process at first, but in the long run, its benefits are clear. Unit testing ensures that all code meets quality standards before it’s deployed. This ensures a reliable engineering environment where quality is paramount. Over the course of the product development life cycle, unit testing saves time and money, and helps developers write better code, more efficiently.
Editor’s note: The article was first published on July 15, 2017, and was updated for relevancy and accuracy on December 10, 2020.