Visual Studio 2013 和 2015 中的 OpenCover 和 ReportGenerator 单元测试覆盖率
Visual Studio 2013 和 2015 中的 OpenCover 和 ReportGenerator 单元测试覆盖率
在 Visual Studio 中获取代码覆盖率指标的常用方法是购买 Visual Studio Enterprise 版本或购买 dotCover 第三方工具,这两者都价格昂贵,特别是如果您自己开发小型应用程序并希望检查单元测试的覆盖率。
有一个免费的 NuGet 包,用于生成代码覆盖率指标,名为 OpenCover,并且与另一个免费的 NuGet 包 ReportGenerator 一起,可以免费为您提供代码覆盖率报告。
然而,我发现的问题是,用于让该工具工作的文档对于我的目的来说不够充分,并且我花费了几个小时来使它为我工作。为了节省您的时间和金钱,我在这里记录了我的经验。
创建本文档时参考了以下内容
- https://nuget.net.cn/packages/OpenCover/
- https://nuget.net.cn/packages/ReportGenerator/
- https://nuget.net.cn/packages/NUnit.ConsoleRunner/
- http://www.allenconway.net/2015/06/using-opencover-and-reportgenerator-to.html
- http://www.nootn.com.au/2014/01/code-coverage-with-opencover-example.html#.VxiNn_krLDc
我已经测试过它在 Visual Studio 2013 Professional 和 Visual Studio 2015 Community Edition 中都有效,并且同时使用 MSTest 和 NUnit。
MSTest 单元测试可以使用 mstest.exe 或较新的 vstest.console.exe 运行。由于我主要使用 NUnit,因此我没有做任何除了基本测试之外的事情来确保 OpenCover 与这两个测试运行程序一起工作,因此无法说明它们在大型项目中的工作方式。
我假设您已经有一个解决方案,其中包含您正在使用测试项目的应用程序项目,并且您正在使用 NUnit 进行该测试,并且您已经包含了 NUnit NuGet 包。
您将需要在 Visual Studio 中打开您的解决方案,并使用程序包管理器控制台获取以下程序包
REM PM> Install-Package OpenCover
REM PM> Install-Package ReportGenerator
如果您使用的是 NUnit 而不是 MSTest,您还需要此包
REM PM> Install-Package NUnit.ConsoleRunner
然后在解决方案根文件夹中,您将需要创建一个批处理文件,用于生成代码覆盖率报告。我提供了三个批处理文件,一个用于使用 NUnit 的情况,一个用于使用 MSTest 和 mstest.exe 测试运行程序的情况,以及一个用于使用 MSTest 和 vstest.console.exe 测试运行程序的情况。
您将需要修改批处理文件以指定包含单元测试的 DLL,即,根据需要更改此行(请注意,%~dp0
是一个符号,它会自动替换为批处理文件的文件夹路径)
SET DllContainingTests=%~dp0WebApp.Tests\bin\Debug\WebApp.Tests.dll
您可能还需要更改应用于结果的筛选器,以排除您不感兴趣代码覆盖率指标的解决方案部分,就我而言,我已要求它包含所有内容(+[*]*
),然后排除我的测试项目(-[*.Tests*]*
)和所有以 Config 结尾的类(-[*]*.*Config
),即
-filter:"+[*]* -[*.Tests*]* -[*]*.*Config"
如果您使用 MSTest,您可能需要将 TestRunnerExe
变量更改为指向正确版本的 mstest.exe 或 vstest.runner.exe。下面的示例指向 Visual Studio 2013 中的文件,但如果您使用 2015,则需要将其更改为 Microsoft Visual Studio 14.0 而不是 Microsoft Visual Studio 12.0。
剩下的就是执行批处理文件以生成代码覆盖率报告,该报告允许您深入了解实际的颜色编码代码是否被覆盖。
NUnit 版本
@ECHO OFF
REM OpenCover-NUnit.bat
REM Run opencover against NUnit tests in your test project and show report of code coverage
REM Derivative work based on work by:
REM Shaun Wilde - https://nuget.net.cn/packages/OpenCover/
REM Daniel Palme - https://nuget.net.cn/packages/ReportGenerator/
REM Charlie Poole - https://nuget.net.cn/packages/NUnit.ConsoleRunner/
REM Allen Conway -
REM http://www.allenconway.net/2015/06/using-opencover-and-reportgenerator-to.html
REM Andrew Newton -
REM http://www.nootn.com.au/2014/01/code-coverage-with-opencover-example.html#.VxiNn_krLDc
SET DllContainingTests=%~dp0WebApp.Tests\bin\Debug\WebApp.Tests.dll
REM *** IMPORTANT - Change DllContainingTests variable (above) to point to the DLL
REM *** in your solution containing your NUnit tests
REM ***
REM *** You may also want to change the include/exclude filters (below)
REM *** for OpenCover
REM ***
REM *** This batch file should dbe placed in the root folder of your solution
REM *** Before being able to use this to generate coverage reports you
REM *** will need the following NuGet packages
REM PM> Install-Package OpenCover
REM PM> Install-Package ReportGenerator
REM PM> Install-Package NUnit.ConsoleRunner
REM
REM NUnit Test Runner (done this way so we dont have to change the code
REM when the version number changes)
for /R "%~dp0packages" %%a in (*) do if /I "%%~nxa"=="nunit3-console.exe" SET TestRunnerExe=%%~dpnxa
REM Get OpenCover Executable (done this way so we dont have to change the
REM code when the version number changes)
for /R "%~dp0packages" %%a in (*) do if /I "%%~nxa"=="OpenCover.Console.exe" SET OpenCoverExe=%%~dpnxa
REM Get Report Generator (done this way so we dont have to change the code
REM when the version number changes)
for /R "%~dp0packages" %%a in (*) do if /I "%%~nxa"=="ReportGenerator.exe"
SET ReportGeneratorExe=%%~dpnxa
REM Create a 'GeneratedReports' folder if it does not exist
if not exist "%~dp0GeneratedReports" mkdir "%~dp0GeneratedReports"
REM Run the tests against the targeted output
call :RunOpenCoverUnitTestMetrics
REM Generate the report output based on the test results
if %errorlevel% equ 0 (
call :RunReportGeneratorOutput
)
REM Launch the report
if %errorlevel% equ 0 (
call :RunLaunchReport
)
exit /b %errorlevel%
:RunOpenCoverUnitTestMetrics
REM *** Change the filter to include/exclude parts of the solution you want
REM *** to check for test coverage
"%OpenCoverExe%" ^
-target:"%TestRunnerExe%" ^
-targetargs:"\"%DllContainingTests%\"" ^
-filter:"+[*]* -[*.Tests*]* -[*]*.*Config" ^
-mergebyhash ^
-skipautoprops ^
-register:user ^
-output:"%~dp0GeneratedReports\CoverageReport.xml"
exit /b %errorlevel%
:RunReportGeneratorOutput
"%ReportGeneratorExe%" ^
-reports:"%~dp0\GeneratedReports\CoverageReport.xml" ^
-targetdir:"%~dp0\GeneratedReports\ReportGenerator Output"
exit /b %errorlevel%
:RunLaunchReport
start "report" "%~dp0\GeneratedReports\ReportGenerator Output\index.htm"
exit /b %errorlevel%
使用 mstest.exe 的 MSTest 版本
@ECHO OFF
REM OpenCover-MSTest.bat
REM Run opencover against MSTest tests in your test project and show report of code coverage
REM Derivative work based on work by:
REM Shaun Wilde - https://nuget.net.cn/packages/OpenCover/
REM Daniel Palme - https://nuget.net.cn/packages/ReportGenerator/
REM Allen Conway -
REM http://www.allenconway.net/2015/06/using-opencover-and-reportgenerator-to.html
REM Andrew Newton -
REM http://www.nootn.com.au/2014/01/code-coverage-with-opencover-example.html#.VxiNn_krLDc
SET DllContainingTests=%~dp0WebApp.Tests\bin\Debug\WebApp.Tests.dll
REM *** IMPORTANT - Change DllContainingTests variable (above) to point to the DLL
REM *** in your solution containing your NUnit tests
REM ***
REM *** You may also want to change the include/exclude filters
REM *** (below) for OpenCover
REM ***
REM *** This batch file should dbe placed in the root folder of your solution
REM *** Before being able to use this to generate coverage reports you will
REM *** need the following NuGet packages
REM PM> Install-Package OpenCover
REM PM> Install-Package ReportGenerator
REM
REM *** MSTest Test Runner (VS2013, will need to change 12.0 to 14.0 for VS2015)
SET TestRunnerExe=%PROGRAMFILES(X86)%\Microsoft Visual Studio 12.0\Common7\IDE\MSTest.exe
REM Get OpenCover Executable (done this way so we dont have to change
REM the code when the version number changes)
for /R "%~dp0packages" %%a in (*) do if /I "%%~nxa"=="OpenCover.Console.exe" SET OpenCoverExe=%%~dpnxa
REM Get Report Generator (done this way so we dont have to change the code
REM when the version number changes)
for /R "%~dp0packages" %%a in (*) do if /I "%%~nxa"=="ReportGenerator.exe"
SET ReportGeneratorExe=%%~dpnxa
REM Create a 'GeneratedReports' folder if it does not exist
if not exist "%~dp0GeneratedReports" mkdir "%~dp0GeneratedReports"
REM Run the tests against the targeted output
call :RunOpenCoverUnitTestMetrics
REM Generate the report output based on the test results
if %errorlevel% equ 0 (
call :RunReportGeneratorOutput
)
REM Launch the report
if %errorlevel% equ 0 (
call :RunLaunchReport
)
exit /b %errorlevel%
:RunOpenCoverUnitTestMetrics
REM *** Change the filter to include/exclude parts of the solution you want to
REM *** check for test coverage
"%OpenCoverExe%" ^
-target:"%TestRunnerExe%" ^
-targetargs:"/noisolation /testcontainer:\"%DllContainingTests%\"" ^
-filter:"+[*]* -[*.Tests*]* -[*]*.Global -[*]*.RouteConfig -[*]*.WebApiConfig" ^
-mergebyhash ^
-skipautoprops ^
-register:user ^
-output:"%~dp0GeneratedReports\CoverageReport.xml"
exit /b %errorlevel%
:RunReportGeneratorOutput
"%ReportGeneratorExe%" ^
-reports:"%~dp0\GeneratedReports\CoverageReport.xml" ^
-targetdir:"%~dp0\GeneratedReports\ReportGenerator Output"
exit /b %errorlevel%
:RunLaunchReport
start "report" "%~dp0\GeneratedReports\ReportGenerator Output\index.htm"
exit /b %errorlevel%
使用 vstest.console.exe 的 MSTest 版本
@ECHO OFF
REM OpenCover-VSTest.bat
REM Run opencover against MSTest tests in your test project and show report of code coverage
REM Derivative work based on work by:
REM Shaun Wilde - https://nuget.net.cn/packages/OpenCover/
REM Daniel Palme - https://nuget.net.cn/packages/ReportGenerator/
REM Allen Conway -
REM http://www.allenconway.net/2015/06/using-opencover-and-reportgenerator-to.html
REM Andrew Newton -
REM http://www.nootn.com.au/2014/01/code-coverage-with-opencover-example.html#.VxiNn_krLDc
SET DllContainingTests=%~dp0WebApp.Tests\bin\Debug\WebApp.Tests.dll
REM *** IMPORTANT - Change DllContainingTests variable (above) to point to the DLL
REM *** in your solution containing your NUnit tests
REM ***
REM *** You may also want to change the include/exclude filters
REM *** (below) for OpenCover
REM ***
REM *** This batch file should dbe placed in the root folder of your solution
REM *** Before being able to use this to generate coverage reports you will
REM *** need the following NuGet packages
REM PM> Install-Package OpenCover
REM PM> Install-Package ReportGenerator
REM
REM *** MSTest Test Runner (VS2013, will need to change 12.0 to 14.0 for VS2015)
SET TestRunnerExe=%PROGRAMFILES(X86)%\Microsoft Visual Studio 12.0\Common7\IDE\
CommonExtensions\Microsoft\TestWindow\vstest.console.exe
REM Get OpenCover Executable (done this way so we dont have to change
REM the code when the version number changes)
for /R "%~dp0packages" %%a in (*) do if /I "%%~nxa"=="OpenCover.Console.exe" SET OpenCoverExe=%%~dpnxa
REM Get Report Generator (done this way so we dont have to change the code
REM when the version number changes)
for /R "%~dp0packages" %%a in (*) do if /I "%%~nxa"=="ReportGenerator.exe"
SET ReportGeneratorExe=%%~dpnxa
REM Create a 'GeneratedReports' folder if it does not exist
if not exist "%~dp0GeneratedReports" mkdir "%~dp0GeneratedReports"
REM Run the tests against the targeted output
call :RunOpenCoverUnitTestMetrics
REM Generate the report output based on the test results
if %errorlevel% equ 0 (
call :RunReportGeneratorOutput
)
REM Launch the report
if %errorlevel% equ 0 (
call :RunLaunchReport
)
exit /b %errorlevel%
:RunOpenCoverUnitTestMetrics
REM *** Change the filter to include/exclude parts of the solution you want to
REM *** check for test coverage
"%OpenCoverExe%" ^
-target:"%TestRunnerExe%" ^
-targetargs:"\"%DllContainingTests%\"" ^
-filter:"+[*]* -[*.Tests*]* -[*]*.Global -[*]*.RouteConfig -[*]*.WebApiConfig" ^
-mergebyhash ^
-skipautoprops ^
-register:user ^
-output:"%~dp0GeneratedReports\CoverageReport.xml"
exit /b %errorlevel%
:RunReportGeneratorOutput
"%ReportGeneratorExe%" ^
-reports:"%~dp0\GeneratedReports\CoverageReport.xml" ^
-targetdir:"%~dp0\GeneratedReports\ReportGenerator Output"
exit /b %errorlevel%
:RunLaunchReport
start "report" "%~dp0\GeneratedReports\ReportGenerator Output\index.htm"
exit /b %errorlevel%