The (misguided) quest for 100% (unit) test coverage


WARNING: This post contains opinions and perspectives that may be controversial. The views expressed here are intended to be pragmatic and based on years of real-world experience with CICD and automated testing, rather than automatically adhering to dogmatic new-age development methodologies. So chill, and please post well thought out and balanced comments letting me know how wrong I am.

Introduction

Over a (long enough) stint in the software industry, I've witnessed the ebb and flow of numerous development methodologies, tools, and practices.

While each claimed to be the panacea for software quality and productivity, the reality is often more nuanced.

One such topic that has consistently made my eyes roll is the singular focus on achieving 100% unit test coverage, often at the expense of a more holistic and pragmatic testing approaches.

The Allure of Unit Test Coverage Metrics

In the early days of my career, automated testing was a somewhat of luxury reserved for teams with ample resources and foresight. We all remember the Quality Assurance teams of not too long ago, with test scripts that we couldn't wait to automate away.  As the industry matured, tools and frameworks emerged that made automated testing more accessible, end to end, integration, and yes unit tests.

In time, developers gained the ability to generate metrics that quantified their testing efforts, and more recently the team/corporate mandates of achieving 100% unit test coverage followed.  Unit tests are in an enviable position in terms of quantifying the coverage.  If there is a way to measure 100% end to end or integration test coverage, I am all ears...

The allure of this 100% coverage metric is understandable. It's a tangible, measurable goal that can be easily tracked and reported. Teams could take pride in their "green" builds, indicating complete test coverage.

Managers and stakeholders could point to these numbers as evidence of quality. However, as I've seen through my own experience and the heard the experience of others who are able to challenge the "sacred cow" status of unit tests: These metrics can be deceptive, implying things that don't survive superficial scrutiny, and often create a false sense of security.

The Limitations of Unit Tests

Don't get me wrong; unit tests are valuable tools in a developer's arsenal. They allow us to verify the behavior of individual components and functions, catch regressions, and facilitate refactoring.

However, they are inherently limited in scope. Unit tests are analogous to testing the individual parts of a complex system – an essential step, but one that provides no guarantees about the system's overall functionality.

As an example, just as meticulously testing every component of an airplane design does not guarantee that the final production aircraft will fly, relying solely on unit tests can lead to oversights and failures when deploying applications through the all-too-common "Push the code and deploy straight into production" CICD pipelines.

I have (we all have?) seen too many instances where an application with 100% unit test coverage fails to start up or exhibits critical bugs in production environments.  The airplane did not fly...

A truer measure of quality: End-to-end and integration testing

Over the years, I've come to accept that the true measure of an application's readiness for production should be its ability to pass comprehensive end-to-end tests that validate the system as a whole.

These tests simulate real-world user scenarios and interactions, ensuring that all components work together seamlessly.

Integration tests, which validate the interaction between different modules or services, are also crucial for identifying issues that may not manifest at the unit level.

Unfortunately, end-to-end and integration testing are often neglected in favor of pursuing the more elusive goal of 100% unit test coverage.

Teams become so focused on satisfying dogma riddled and arbitrary metrics that they lose sight of the bigger picture: Delivering a high-quality, well-tested product that meets the needs of end-users.

Re-balancing Our Approach to Automated Testing

Maybe it's time to re-evaluate our approach to automated testing and shift more of our focus towards end-to-end and integration testing.

These tests can be the primary concern, encompassing critical user flows and verifying the application's behavior from the user's perspective. Unit tests can play a supporting role, primarily used for testing libraries and key logic components to prevent regressions.

A shift in mindset doesn't mean abandoning unit tests altogether. They still have value, particularly in facilitating refactoring and catching low-level bugs. However, they should not be the sole focus of our testing efforts, nor should we obsess over achieving arbitrary coverage metrics.

Instead, we should allocate (a lot more) more of our limited time and resources into developing comprehensive end-to-end and integration tests. These tests may be more complex and time-consuming to create and maintain, but they provide a more holistic evaluation and true measure of an application's readiness for production deployment.

Conclusion

As I look back on my career, I've learned that software development is a constant exercise in balancing trade-offs and prioritizing efforts.

The pursuit of 100% unit test coverage is a tempting goal, but it can lead us astray if we lose sight of the larger objective: delivering high-quality software that meets the needs of end-users.

Maybe it's time to critically examine the prevailing wisdom and question the hype surrounding unit test coverage metrics. While these metrics have their place, they should not be the sole arbiter of quality or the primary focus of our automated testing strategies.

By re-balancing our approach and prioritizing end-to-end and integration testing, we can increase the reliability and quality of our software while optimizing the use of limited testing resources. In the end, it's not about chasing arbitrary numbers but about delivering robust, well-tested applications that work well and stand the test of time.

Nixon Cheaz
I am a technical lead in the area of Site Search and an engineering manager for a large Fortune 500 technology company by day.
Cary, NC USA