You might remember my earlier post where I described how to set up code coverage reporting for .NET Core 3 using AppVeyor + OpenCover + Codecov.
Time has moved on, .NET 5 has arrived, and the best practices have changed, so let's see how to collect code coverage for .NET projects in 2021.
For some time, I have been intrigued by the
coverlet.collector that you can find in any new XUnit
.csproj. What it is? How can I use it? Can I replace OpenCover with it?
Also, I started noticing people migrating to GitHub Actions and I didn't have any experience with it and kinda felt that I'm missing the train. This observation has been confirmed recently in the 2020 State of Open Source Code Coverage report where GitHub Actions scored the #1 fastest growing CI used with Codecov (and also the #1 in absolute numbers).
I was thinking I could modernize the stack that I use for .NET projects both at work and for my personal projects. Of the three tools that I've been using previously, I'll be keeping just Codecov (because it's awesome ❤). Let's get to it.
I like to use the
dotnet CLI for as many tasks as possible. The good news is that
coverlet offers deep integration with
This is how you can generate code coverage for the whole solution:
dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
The command will generate
coverage.opencover.xml files in all your test projects (if you run
dotnet test on the solution level).
All you need to do to make the code coverage-related
/p: switches work is to install also the
coverlet.msbuild NuGet package. So your
.csprojs will look something like this:
<PackageReference Include="coverlet.collector" Version="3.0.3"> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <PrivateAssets>all</PrivateAssets> </PackageReference> <PackageReference Include="coverlet.msbuild" Version="3.0.3"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference>
Make sure to leave in the
/p:CoverletOutputFormat=opencover switch as this is the format that's accepted by Codecov.
For more advanced configuration, I recommend reading the documentation on Coverlet's integration with MSBuild. This is especially useful when your solution or projects don't stick to naming conventions and you need to do some extra filtering, etc.
dotnet test into the CI pipeline is just a matter of creating a new workflow step. No matter if you use the
windows-latest runner, it works flawlessly.
- name: Restore dependencies run: dotnet restore - name: Build run: dotnet build --no-restore /p:ContinuousIntegrationBuild=true - name: Test run: dotnet test --no-build --verbosity normal /p:CollectCoverage=true /p:CoverletOutputFormat=opencover
The last step is to upload the test coverage to Codecov. You can find an official Codecov GitHub Action on the marketplace which makes the process super easy - no need to install the Codecov CLI, etc.
Just add the following lines to your workflow:
- name: Codecov uses: codecov/codecov-action@v1
Codecov will search through the folder structure of your project and discover your coverage reports based on conventions. You don't even have to include the
CODECOV_TOKEN for public repos.
As you can see, this approach is much more convenient than the one I was using before - downloading and installing tools, running PowerShell scripts, etc.
If you stick to standard .NET naming and folder structure conventions, setting up code coverage is actually very easy nowadays.
In my next article, I'll cover how to secure secrets when building pull requests from forks.