Code Coverage Testing in C#: From Metrics to Quality

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why "Green" Tests Are Not Yet a Victory?

\n\n

Imagine: you wrote a hundred unit tests, they all pass with a green checkmark, the CI pipeline is happy, the manager is pleased. But a month later, critical functionality fails in production. Sound familiar? Most often, the problem is that we are testing the wrong scenarios or skipping entire code branches.

\n\n

Code coverage is not just a trendy metric for a report. It is your flashlight in a dark room of uncertainty. When I started working with C#, I thought 80% coverage was the ideal. But then I realized: you can have 100% line coverage and still miss a bug in branching logic. So today we will figure out how to correctly measure coverage in C#, which tools really help, and which metrics are worth tracking.

\n\n

What is Code Coverage and Why is it Important for a C# Developer?

\n\n

Simply put, code coverage shows what percentage of your application's source code was executed during test runs. If you wrote a test that calls the CalculateDiscount() method but does not check the if (isPremiumUser) branch, then that branch remains "uncovered."

\n\n

For a C# developer, coverage is an indicator of two things:

\n
    \n
  • Confidence in refactoring — can you change the code without fear of breaking something?
  • \n
  • Test completeness — have we forgotten about edge cases?
  • \n
\n\n

But there is an important nuance: code coverage in C# does not guarantee the absence of bugs. It only tells you that certain lines were executed. That is why we look not just at the percentage, but at specific metrics.

\n\n

Key Code Coverage Metrics in .NET

\n\n

When you run coverage analysis in C#, you encounter several types of metrics. Let's break down each one using real code examples.

\n\n

Line Coverage

\n

The simplest metric. It counts how many lines of code were touched by tests. Example:

\n\n
public int Add(int a, int b)\n{\n    if (a < 0)          // line 1\n        return 0;       // line 2\n    return a + b;        // line 3\n}
\n\n

If your test calls Add(5, 3), then lines 1 and 3 will be executed. Line 2 will remain uncovered. Line coverage will show 66% (2 out of 3 lines).

\n\n

Branch Coverage

\n

A more honest metric. It accounts for all possible execution paths. In our example, there are two paths: when a < 0 and when it is not. If you only tested the case with a positive number, Branch coverage will be 50%.

\n\n

It is Branch coverage that often reveals "holes" in tests. I recommend aiming for 80%+ specifically on this metric.

\n\n

Cyclomatic Complexity and its Relationship to Coverage

\n

Although this is not a direct coverage metric, cyclomatic complexity shows how many tests need to be written for full coverage. The higher the complexity of a method, the more tests are required. If you see a method with a cyclomatic complexity of 15 and 90% coverage, you are likely not testing all scenarios.

\n\n

Tools for Measuring Code Coverage in C#

\n\n

The .NET ecosystem has several powerful tools. I will talk about the three most popular ones that I have worked with myself.

\n\n

Coverlet — Free and Built into .NET

\n

If you are using .NET 6+, Coverlet is already available via NuGet. This is my favorite tool for CI/CD because it does not require installing additional programs.

\n\n

Installation:

\n
dotnet add package coverlet.msbuild\ndotnet add package coverlet.collector
\n\n

Running with a report:

\n
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
\n\n

You will get a coverage.opencover.xml file, which can be visualized using ReportGenerator:

\n
dotnet tool install -g dotnet-reportgenerator-globaltool\nreportgenerat                

Blogs

Book Recommendations