What is code coverage and what is a good coverage percentage?

4 minbeginnertestingcode-coveragequality

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.