Using OpenCover and xUnit
When I am writing tests I find it useful to have a coverage tool. Since NCover is no longer free I have started to use OpenCover I like OpenCover, it is a mature product that works well and as a free open source project its great for my personal projects. I also use the excellent ReportGenerator to format the output from OpenCover.
I recently needed to use a coverage tool to work with some xUnit tests and I knocked together some scripts but it turned out to be a bit more complex than I thought.
For this example I used an example app “MyApp” which contained a class called ObjectUnderTest and I wrote some tests in MyApp.Tests. I’ve installed OpenCover to its default location in C:\Users\derek.wilson\AppData\Local\Apps\OpenCover and ReportGenerator does not really install so I have just copied it into a folder called ReportGenerator in the same location as OpenCover. xUnit is also installed in its default location.
The command script to run the tests that I first put together looked like this
C:\Users\derek.wilson\AppData\Local\Apps\OpenCover\opencover.console -output:coverage.xml -target:"C:\Program Files (x86)\xUnit\xunit.console.clr4.exe" -targetargs:"MyApp.Tests\bin\Debug\MyApp.Tests.dll" -filter:"+[*]MyApp.* -[*.Tests]*" C:\Users\derek.wilson\AppData\Local\Apps\ReportGenerator\bin\reportgenerator coverage.xml .\coverage start .\coverage\index.htm
The mechanism here is that I get “opencover.console” to use “xunit.console.clr4.exe” to run the tests in the MyApp.Tests.dll, however all we see is this
xUnit.net console test runner (64-bit .NET 4.0.30319.269) Copyright (C) 2007-11 Microsoft Corporation. xunit.dll: Version 1.8.0.1549 Test assembly: C:\POC\MyApp\MyApp.Tests\bin\Debug\MyApp.Tests.dll 3 total, 0 failed, 0 skipped, took 0.251 seconds Committing... No results - no assemblies that matched the supplied filter were instrumented (missing PDBs?)
In the documentation for OpenCover it does recommend that the profiler be registered so I registered the 64bit version as I was running on a 64 bit OS.
regsvr32 C:\Users\derek.wilson\AppData\Local\Apps\OpenCover\x64\OpenCover.Profiler.dll
However it still did not work. It turns out that I needed to specify the xUnit noshadow switch, I did this in an xunit project file as I was going to need one anyway as soon as I had more than a few DLLs, like this
<?xml version="1.0" encoding="utf-8"?> <xunit> <assemblies> <assembly filename="MyApp.Tests\bin\Debug\MyApp.Tests.dll" shadow-copy="false" /> </assemblies> </xunit>
I then changed the script to use the xunit project file like this
C:\Users\derek.wilson\AppData\Local\Apps\OpenCover\opencover.console -output:coverage.xml -target:"C:\Program Files (x86)\xUnit\xunit.console.clr4.exe" -targetargs:"MyApp.xunit" -filter:"+[*]MyApp.* -[*.Tests]*" C:\Users\derek.wilson\AppData\Local\Apps\ReportGenerator\bin\reportgenerator coverage.xml .\coverage start .\coverage\index.htm
And it started to work – like this
xUnit.net console test runner (64-bit .NET 4.0.30319.269) Copyright (C) 2007-11 Microsoft Corporation. xunit.dll: Version 1.8.0.1549 Test assembly: C:\MyApp\MyApp.Tests\bin\Debug\MyApp.Tests.dll 3 total, 0 failed, 0 skipped, took 0.546 seconds Committing... Visited Classes 1 of 1 (100) Visited Methods 1 of 1 (100) Visited Points 9 of 9 (100) Visited Branches 4 of 4 (100) ==== Alternative Results (includes all methods including those without corresponding source) ==== Alternative Visited Classes 1 of 1 (100) Alternative Visited Methods 6 of 6 (100) C:\MyApp>C:\Users\derek.wilson\AppData\Local\Apps\ReportGenerator\bin\reportgenerator coverage.xml .\coverage Loading report 'coverage.xml' Initiating parser for OpenCover Current Assembly: MyApp Analyzing 1 classes Creating report 1/1 (Assembly: MyApp, Class: MyApp.ObjectUnderTest) Creating summary Report generation took 0 seconds
Not only did it work I did not have to run the script as an administrator