An argument can be made that unit tests are not worth the time and energy that they cost to produce. Furthermore, after investing that time and cost there is no guarantee that writing unit tests will catch every issue. While these are all valid arguments, utilizing unit testing for your solution is an excellent way to produce better quality code and save both money and time in the long run. An investment in a unit testing suite will improve system reliability and reduce future development cost.
Not Enough Time
Without fail, time is the first topic raised by every developer arguing against unit testing. In many cases this is a very valid concern, especially when developers have deadlines. After all, who has time to write unit tests for every block of code that is added to the system? This perspective, although valid, is naive and shortsighted. The technical debt created by not following good unit testing practices will be paid for in the regression testing that must be done after development.
In order to understand that time really is not a problem requires one to look at the big picture. If tests get created for each feature added to the system, you can continue to make changes and updates with increasing certainty that you won’t break something. If tests are set up around the existing code and they are passing, you have a baseline to prove that new code doesn’t introduce new bugs. Aside from the benefits as the code base expands, unit tests also validate the code before it is moved to any environment.
Regression testing benefits aside, unit testing also enables you to have quicker release times. Without unit testing, a regression-style bug that breaks existing functionality could more easily make it into the code base. As a result, the QA team finds and reports on the bug, resulting in a developer needing to context switch and spend additional time fixing the bug. If the QA team doesn’t catch the bug, the lack of unit tests could affect end-users and trigger escalations. By trying to save time by not writing unit tests, the entire software life-cycle comes to a halt intermittently. More people are spending more of their time trying to track down issues that could have been caught during development.
Often discussed in tandem with time is the topic of budget. Budget is a topic that often comes up after a project is underway and after kinks have cropped up, causing timelines to be adjusted. Often in these cases, stakeholders and project leadership will look for ways to speed things up, accelerating the development pipeline. It can be appetizing to think about trimming the unit testing fat out of the scope of the project to stay within budget – don’t fall into the trap!
By cutting out unit testing, the initial development processing can be quicker but at the expense of introducing more bugs and generally lower-quality code. By saving development time, more weight is placed on QA and future development teams. Any future development that modifies or extends the untested code will be more difficult to validate and verify. Initially, it will appear like project velocity is increasing and the budget is safe, but it can easily all fall apart.
As previously discussed, the more people that are impacted by increased bug and regression rates, the more cost is sunk into technical debt. With each higher environment bugs progress through, the time and cost required to fix the bug will be larger. Once again, the marginal cost of unit testing during the development process can pay dividends in the long run.
Unit Testing Won’t Catch Everything Anyway
Unit tests won’t catch everything.
This is a fact and there is no escaping it. No matter how many unit tests you write, you will never test every test case in a complex system. Unit tests are the foundation of the testing pyramid, providing a stable foundation on which integration and end-to-end testing can provide maximum value. Without a solid foundation, the rest of the pyramid provides less value and costs more to produce.
To effectively build the base of the testing pyramid, the majority of the test suite needs to consist of unit tests. While it is accurate to say that unit tests will not catch everything, it is completely wrong to skip over the unit testing just because it is not a complete testing solution. Each type of testing provides its own benefits and covers a different part of the system. It is only together that the different types of testing are most effective.
Having a solid suite of unit tests that test the lowest-level of functionality provides a solid base for the other tests to build upon. Integration and end-to-end tests can focus on integrations and user experience, knowing that the internals of the system have already been asserted to work correctly. This leads to a comprehensive testing suite that has increased coverage and lower overall costs. Investing in unit tests as a strong foundation is integral to application reliability.
These three arguments are some of the most common that come up during conversations around unit testing. Perhaps this defense of unit testing will convince you to give unit testing a chance and see if it helps your development process. If nothing else, hopefully it provides you with some talking points against the typical arguments that come up in opposition of spending the time and effort to implement unit tests.
While there are some who may argue that spending time and effort to implement unit testing is fruitless, the pay-off in the long run is immense. Organizations can both save money and produce higher quality code, all while improving the application test-ability and reliability. I have yet to find an organization that did not appreciate the results of having a strong unit testing suite when code shipped to production.