What is code coverage and what is a good coverage percentage?
Quick Answer
Code coverage measures the percentage of code (lines, branches, methods) executed by your tests, highlighting untested areas. It's a useful signal but not a quality guarantee — high coverage with weak assertions proves little. Aim for meaningful coverage of important logic (often ~70-80% is a pragmatic target) rather than chasing 100%, and prioritize testing complex, high-risk paths.
Detailed Answer
Code Coverage is a metric that measures the percentage of code executed during automated tests. It shows which parts of your codebase are tested and which aren't.
Types of Coverage:
1. Line Coverage: Percentage of code lines executed 2. Branch Coverage: Percentage of decision branches taken (if/else, switch) 3. Method Coverage: Percentage of methods called 4. Statement Coverage: Percentage of statements executed
Example:
public int Divide(int a, int b)
{
if (b == 0) // Branch 1
throw new DivideByZeroException();
return a / b; // Branch 2
}
// Test only happy path = 50% branch coverage
[Fact]
public void Divide_ValidNumbers_ReturnsQuotient()
{
var result = calculator.Divide(10, 2);
Assert.Equal(5, result);
}
// Test both branches = 100% branch coverage
[Fact]
public void Divide_ByZero_ThrowsException()
{
Assert.Throws(() => calculator.Divide(10, 0));
}
What is a "good" coverage percentage?
The Nuanced Answer: There's no magic number, but context matters:
- 80-90% is often cited as a good target
- 100% is usually unrealistic and unnecessary
- Below 70% suggests insufficient testing
Important Considerations:
Coverage doesn't equal quality:
- 100% coverage doesn't mean bug-free code
- You can have high coverage with poor assertions
- Focus on meaningful tests, not just coverage numbers
// Bad: 100% coverage, but useless test
[Fact]
public void Add_TwoNumbers_DoesNotThrow()
{
var result = calculator.Add(2, 3);
// No assertion! But technically covers the line
}
// Good: Lower coverage, but actually validates behavior
[Fact]
public void Add_TwoNumbers_ReturnsCorrectSum()
{
var result = calculator.Add(2, 3);
Assert.Equal(5, result);
}
What to focus on:
- Critical business logic: Aim for 90%+
- Complex algorithms: High coverage essential
- Simple getters/setters: Don't obsess over coverage
- Generated code: Often excluded from coverage
- Configuration code: Lower priority
Better metrics to combine with coverage:
- Mutation testing (tests' ability to catch bugs)
- Code review quality
- Defect rates in production
- Test execution time
Tools for .NET:
- Coverlet
- dotCover (JetBrains)
- NCover
- Visual Studio Code Coverage
Conclusion: Aim for 80%+ coverage, but prioritize meaningful tests over hitting a number. High coverage with poor tests is worse than moderate coverage with excellent tests.