Why 100% Code Coverage Won't Save Your Codebase
Code coverage is one of the most frequently discussed metrics in software development. It’s easy to see why—having a high percentage of tested code feels like a badge of honor for any team. But here’s the harsh truth: code coverage alone doesn’t ensure code quality.
While coverage numbers can give you a sense of how much of your code is tested, they don’t tell you
If your tests are meaningful.
Whether your code is maintainable.
If your software truly meets user needs.
In fact, relying solely on code coverage can lead to a false sense of security, where teams chase the metric instead of focusing on building robust, reliable, and high-quality applications.
In this blog, we’ll explore the limitations of code coverage as a metric, why achieving 100% coverage is not the ultimate goal, and what you should focus on instead to ensure your code is both well-tested and high-quality.
How is code coverage calculated?
Before we strive to achieve 100% code coverage, lets understand how is it calculated.
Consider this function to calculate grades,
function calculateGrade(score) {
if (score >= 90) {
return 'A';
} else if (score >= 80) {
return 'B';
} else if (score >= 70) {
return 'C';
} else {
return 'F';
}
}
The function roughly consists of 7-8 lines excluding line having just { or }. The % of number of lines of code executed by my test case is called Code Coverage.
For example, if i write test cases for scores range between 70-80-90 my code coverage would roughly be 70-80% because my test cases execute 6 lines of code in calculateGrade function.
$$Coverage Percentage=( Lines Executed / Total Lines )×100$$
Why 100% code coverage alone doesn’t make sense?
In the above function, if i write test cases for scores ranging from 50 - 90 i can easily achieve 100% code coverage.
But ask yourselves, did we really cover everything? Didn’t we write test-cases to cover just the happy case scenarios? Can we really ship this code with confidence?
I hope your answer is a Big NO! 🙈
So what would really help us ship this code with confidence?
Writing Robust Code
Writing Relevant Test Cases aka Feature Coverage.
Writing Negative Test Cases
I hope you noticed that the function is not robust enough to handle all the scenarios.
The function cannot handle empty score, out of range score, invalid data type of score argument.
These negative test-cases are essentially 3 bugs avoided even before we ship the code.
function isValidScore(score){
// You can add more failure scenarios according to your usecase.
const invalidScoreScenarios = !score || !(typeof score === 'number')
|| !(0 <= score <=100);
if(invalidScoreScenarios){
return false;
}
return true;
}
function calculateGrade(score) {
// This score validation function is what makes your code robust.
if(!isValidScore()){
throw new Error('Please check your score again.')
}
if (score >= 90) {
return 'A';
} else if (score >= 80) {
return 'B';
} else if (score >= 70) {
return 'C';
} else {
return 'F';
}
}
Now that our function is more robust, we can write test-cases to test all valid score scenarios which will improve our code coverage & with each negative test case we write, we lessen the chances of bugs.
Remember, to make this code bug free, we have to think of negative scenarios that might break the function & then write robust code to deal with it.
All of these things will help us ship the code with confidence 😎
Please like & comment if you found this helpful 😄
I’m also open to any improvements or suggestions ❤️
Subscribe to my newsletter
Read articles from Varun Kelkar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Varun Kelkar
Varun Kelkar
Javascript | React | Node | Lit Web Components | Microfrontends