Why "Green" Tests Are Not Yet a Victory?
\n\nImagine: 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\nCode 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\nWhat is Code Coverage and Why is it Important for a C# Developer?
\n\nSimply 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."
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
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\nKey Code Coverage Metrics in .NET
\n\nWhen you run coverage analysis in C#, you encounter several types of metrics. Let's break down each one using real code examples.
\n\nLine Coverage
\nThe simplest metric. It counts how many lines of code were touched by tests. Example:
\n\npublic 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\nIf 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).
Branch Coverage
\nA 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%.
It is Branch coverage that often reveals "holes" in tests. I recommend aiming for 80%+ specifically on this metric.
\n\nCyclomatic Complexity and its Relationship to Coverage
\nAlthough 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\nTools for Measuring Code Coverage in C#
\n\nThe .NET ecosystem has several powerful tools. I will talk about the three most popular ones that I have worked with myself.
\n\nCoverlet — Free and Built into .NET
\nIf 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\nInstallation:
\ndotnet add package coverlet.msbuild\ndotnet add package coverlet.collector\n\nRunning with a report:
\ndotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover\n\nYou will get a coverage.opencover.xml file, which can be visualized using ReportGenerator:
dotnet tool install -g dotnet-reportgenerator-globaltool\nreportgenerat