Introduction
OpenCover is a free, open-sourced, code coverage tool for .NET 2.0 and above running on the .NET platform. It supports sequence coverage, branch coverage and has a cover by test facility. Though OpenCover is command line only, a rich HTML UI of the results can be visualized using ReportGenerator.
We will aim to demonstrate how you can use this utility to get visibility into your testing coverage.
Background
OpenCover is currently the only actively developed and maintained open-sourced tool of it's type for the .NET platform but it was not the first, some of the others being:
NCover
- Probably the most well-known commercial tool for .NET code coverage started life as an open-source project.
Coverage.eye
- Originated at Microsoft and was available on gotdotnet, the repository/sample has since gone and no full mirrors appear to exist (The wayback machine only has the text).
PartCover
- This appears to have been created in response to NCover going commercial and though actively used it has limitations e.g. 32-bit only. The original repository is no longer being maintained by its original developers and is now being maintained on github.
Using OpenCover
Preparing for OpenCover
The following steps detail how to download OpenCover (and other supporting tools) from NuGet.
OpenCover is available as a zip or msi download via its bitbucket mirror but for the sake of this article we will use the OpenCover nuget package.
- Create a new solution
- For that solution "Enable NuGet Package Restore"
- Using "Manage NuGet Packages for Solution" add the following packages
OpenCover
ReportGenerator
NUnit.Runners
Once completed you should have a solution with a .nuget folder which contains a packages.config that looks something like the following
="1.0"="utf-8"
<packages>
<package id="NUnit.Runners" version="2.6.3" />
<package id="OpenCover" version="4.5.1923" />
<package id="ReportGenerator" version="1.9.1.0" />
</packages> <span style="color: rgb(17, 17, 17); font-family: 'Segoe UI', Arial, sans-serif; font-size: 14px;"> </span>
Next
- Create a C# project (class library) called Sample
- Create a C# project (class library) called Sample.Test and reference the Sample project
- Use NuGet to add the following package
NUnit
Now to add a simple class and method and a test that will exercise that method.
In the Sample project add the following class
public class Target
{
public static void DoSomething()
{
try
{
Console.WriteLine("I ran!");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
In the Sample.Test project add the following class
using NUnit.Framework;
[TestFixture]
public class TargetTest
{
[Test]
public void DoSomethingTest()
{
Target.DoSomething();
}
}
Running tests with OpenCover
OpenCover does not directly execute your tests but instead needs to execute another application that executes your tests in this case we are using NUnit.
First lets create a batch file that we can execute our tests from the command line
..\..\..\packages\NUnit.Runners.2.6.3\tools\nunit-console.exe sample.test.dll /noshadow
This batch file can be added to the Sample.Test project (with Copy to Output Directory set to Copy Always).
Now we can use OpenCover to execute this batch file, again we can add this as a a batch file to our Sample.Test project so that we can execute it on the command line
..\..\..\packages\OpenCover.4.5.1923\OpenCover.Console.exe -target:runtests.bat -register:user -filter:+[Sample]*
The arguments are
-target:
- used to indicate the target process for OpenCover to execute.
-register:user
- used to register the COM objects that OpenCover uses to instrument your assemblies.
-filter:
- used to control which assemblies OpenCover will gather coverage data for. The filter is capable of including and excluding assemblies and classes and is actually the same filter format that PartCover uses. The filter is one of the more complex features of OpenCover and more detail is provided with the documentation that is installed alongside OpenCover or in the Usage wiki.
When executed, OpenCover will produce an XML file (default results.xml) that contains all the data related to that test run. To visualize that data we can use ReportGenerator to produce some rich HTML output. ReportGenrator can also be run on the command line
..\..\..\packages\ReportGenerator.1.9.1.0\reportgenerator.exe -reports:results.xml -targetdir:coverage
If we open the produced coverage output (coverage\index.htm) we can see the visualization of the coverage of our target code.
| | 7 | namespace Sample |
| | 8 | { |
| | 9 | public class Target |
| | 10 | { |
| | 11 | public static void DoSomething() |
| 1 | 12 | { |
| | 13 | try |
| 1 | 14 | { |
| 1 | 15 | Console.WriteLine("I ran!"); |
| 1 | 16 | } |
| 0 | 17 | catch (Exception ex) |
| 0 | 18 | { |
| 0 | 19 | Console.WriteLine(ex.Message); |
| 0 | 20 | } |
| 1 | 21 | } |
| | 22 | } |
| | 23 | } |
As you can see it is quite simple to understand what code your tests actually cover.
For a real-world example OpenCover is actually used to gather coverage on it's own tests and the results can be seen on the OpenCover build pipeline.
History
Nov 3rd 2013 - Original Article