基于OpenCover进行代码覆盖率测试

时间:2024-04-16 07:52:23

  最近开始接触白盒测试,开发同事对OpenCover(开源C#代码覆盖率统计工具)、ReportGenerator(将XML报告转换成HTML的工具)二次开发出一个代码覆盖率的工具。下面基于该工具,记录对OpenCover、ReportGenerator等的理解。

 

未使用OpenCover时,被测程序的正常运行流程:

使用OpenCover、ReportGenerator后,被测程序的运行流程:

  OpenCover中的Profiler启动运行被测程序的程序或服务——>运行被测程序——>得到运行结果同时,也得到xml覆盖率结果——>ReportGenerator将xml转成HTML

  ——>命令行调用OpenCover.Console.exe——>使用SentrySdk收集崩溃报告——>解析命令行中传入的参数(被测程序路径、要打印使用说明、是否启动服务、过滤信息等)

  ——>处理过滤器信息,如果命令行中未传-filter参数,则默认匹配分析所有的类和方法——>创建性能计数器?

  ——>得到输出xml报告的全路径——>初始化封装了注入框架依赖的容器——>创建文件句柄,后续将覆盖率信息写入文件中。如果已经存在覆盖率xml文件,则合并

  ——>启动覆盖率分析进程。注册分析器,调用OpenCover.Profiler.dll——>启动被测程序——>

 

 

 

 

该工具使用及主要实现流程:(以测试站点程序为例)

——>配置好OpenCover、ReportGenerator、被测程序的路径、IIS Express config的路径

——>执行的时候就根据配置好的参数执行命令,即相当于在cmd中执行:

H:\白盒测试\Debug\Opencover\OpenCover.Console.exe -target:"C:\Program Files (x86)\IIS Express\iisexpress.exe" -targetdir:"D:\被测站点\xxx.xxx.com\bin" -targetargs:"/site:xxx_bh.xxx.com /config:\"C:\Users\ym\Documents\IISExpress\config\applicationhost.config\"" -register:ym -output:"H:\白盒测试\xml_ym\xxx_bh.xxx.com\xxx_bh.xxx.com.xml"

——>此时IIS Express已经启动,访问在通过IIS Express配置的站点,开始测试。

——>测试完成后,退出IIS Express,生成xml文件。

——>使用ReportGenerator生成HTML文档,相当于在cmd中执行命令:

H:\白盒测试\Debug\ReportGenerator\ReportGenerator.exe -reports:H:\白盒测试\xml\白盒测试.xml -targetdir:H:\白盒测试\xml\html

 

关于OpenCover:

  OpenCover是用于.NET 2.0及以上应用程序的代码覆盖的开源命令行工具。OpenCover使用PDB文件提供序列信息,确定哪行代码与每行源代码相关联,然后检测每个序列点以记录命中。因此必须要有的PDB文件以及可执行文件和程序集,应该在调试模式下构建测试中的应用程序。如果未找到PDB文件,则不会收集任何覆盖数据。

  使用COM(组件对象模型)开发,profiler部分使用c++,

  OpenCover使用mono.Cecil来分析分支或IL以确定在何处检测代码。

  OpenCover在开始时要考虑的指标是:

  1. 声明范围即已涵盖的行数。
  2. 方法覆盖范围,即涵盖了哪些方法。
  3. 分支覆盖范围即采取了哪些分支。这与圈复杂度有关
OpenCover基本用法(命令行参数):
-target: 应用程序可执行文件或服务名称的路径  (我的理解:将被测程序运行起来的程序或服务。网上帖子中,大多用的NUnit。本文例子用的是IIS Express)
-filter应用于选择性地包括或排除coverage结果中的程序集和类的过滤器列表 (默认选择所有的类和方法)
      使用PartCover语法,在哪里(+|-)[Assembly-Filter]Type-Filter
      例如,
+[Open*]*包括以Open开头的程序-[*]Core.*集中的所有类型排除Core命名空间中的所有类型,而不管程序集如何。
      如果未提供过滤器,
+[*]*则会自动应用默认的包含过滤器
-output: 输出XML文件的路径,如果为空,则将在当前目录中创建results.xml -register [:user] - 注册和取消注册代码覆盖率分析器 -targetargs: - 要传递给目标进程的参数(可指定被测程序的路径) -targetdir: - 目标目录的路径或PDB文件的备用路径 (如果-
targetargs 已经指定了被测程序的路径,那么这里可作为查找PDB文件的依据。本文例子则作为查找PDB文件的路径

用法:https://github.com/OpenCover/opencover/wiki/Usage

文档:https://github.com/opencover/opencover/blob/master/main/OpenCover.Documentation/Usage.pdf

参考:http://www.cnblogs.com/binyao/category/477233.html

   http://www.cnblogs.com/tylerzhou/p/9076386.html

   http://blog.alantsai.net/posts/2017/01/devopsseries-opencover-intro

     https://www.codeproject.com/Articles/677691/Getting-code-coverage-from-your-NET-testing-using

 

什么是IIS Express:

  一个兼具Visual Studio的ASP.NET开发服务器和Windows的IIS Web服务器功能的轻量级web服务器。

  具体描述:https://stackify.com/what-is-iis-express/

  配置:https://blog.****.net/zhangjk1993/article/details/36671105

为什么用IIS Express:

文档中有这么一段描述:

Running against IIS
Normally I’d suggest running against IISEXPPRESS as I think it is easier to automate. However for those who really want to run against a full blown IIS then the following instructions (supplied by a user) will hopefully suffice.
“The trick is to start OpenCover to run the w3wp.exe process in debug mode e.g.
OpenCover.Console.exe -target:C:\Windows\System32\inetsrv\w3wp.exe -targetargs:-debug 
-targetdir:C:\Inetpub\wwwwoot\MyWebApp\bin\ -filter:+[*]* -register:user
There are some prerequisites though:
1.All applications running under the site must make use of the same app pool; you\'ll get errors in the EventLog otherwise.
2.inetserver needs to be stopped, before starting w3wp.exe in debug mode. You can use the following command:
net stop w3svc /y
After testing/code coverage completion you can close the w3wp.exe process and start the inetserver again:
net start w3svc
This procedure was tested on a Win2008 machine with IIS7.5”
You can also run multiple OpenCover instances against separate IIS sites by using the –s option when running IIS to choose the siteid e.g.
OpenCover.Console.exe -target:C:\Windows\System32\inetsrv\w3wp.exe 
    -targetargs:"-debug -s 1" 
    -targetdir:%WebSite_Path% 
    -filter:+[*]* 
    -register:user 
    -output:%CoverageResult_Path%
Then you can use ReportGenerator to merge the coverage results. 

大致意思就是用IIS Express更方便。

而如果要启动完整的IIS,那就要:

1)在调试模式下运行被测程序并启动OpenCover(将代码构建到调试模式获取PDB文件。或者直接获取源代码)

2)所有在站点下运行的应用程序都必须使用相同的应用程序池;否则,会报错

3)在调试模式下启动被测程序前,需要停止intserver(PS:intserver可能指的是启动被测程序的服务吧。)

  而结合实际需求,虽然也可以直接往-target传参为IIS的启动程序来进行监控测试情况,但是IIS还部署了其他非测试站点,会相互影响。所以实际应用还是采用IIS Express,每个测试人员部署自己的IIS Express,而不会相互影响。

 

关于PDB文件:

 

  PDBProgram Data Base 的缩写顾名思义,它是一个存储库(持久性存储,如数据库),用于维护在调试模式下运行程序所需的信息。它包含调试代码时所需的许多重要相关信息(在Visual Studio中),例如,在您希望调试器在Visual Studio中中断的位置插入断点。

  这就是为什么如果*.pdb从调试文件夹中删除文件,Visual Studio很多次都无法达到断点的原因Visual Studio调试器还能够通过文件的帮助告诉您堆栈跟踪中发生异常的代码文件的精确行号*.pdb因此,有效的pdb文件在调试程序时对开发人员来说真的很有用。

  通常,建议不要排除*.pdb文件的生成从生产发布的角度来看,您应该做的是创建pdb文件,但不要将它们发送到产品安装程序中的客户站点。将所有生成的PDB文件保留在符号服务器上,以备将来可以使用/引用它。特别适用于调试进程崩溃等问题的情况。当您开始分析故障转储文件时,如果*.pdb未保留在构建过程中创建的原始文件,则Visual Studio将无法确定导致崩溃的确切代码行

  如果您仍想*.pdb为任何版本完全禁用文件生成,请转到项目属性 - >构建选项卡 - >单击Advanced按钮 - > none从“调试信息”下拉框中选择 - >按OK下面的快照中所示。

无C#项目的调试信息设置

 

https://blogs.msdn.microsoft.com/vcblog/2016/02/08/whats-inside-a-pdb-file/

https://tpodolak.com/blog/2017/10/12/net-core-calculating-code-coverage-opencover-windows/

http://www.cnblogs.com/itech/archive/2011/08/15/2136522.html

https://blog.****.net/feihe0755/article/details/54233714

 

使用ReportGenerator 将xml生成HTML报告:

ReportGenerator用于将OpenCoverPartCoverVisual StudioNCover生成的XML报告转换为各种格式的友好可读报告。

使用指南可以在其主页上找到,最有用的命令是(命令行参数):

  • -reports: - 应该解析的覆盖率报告,分号分隔,允许使用通配符
  • -targetdir: - 应保存生成的报告的目录
  • -sourcedirs:[;] [;] - 包含相应源代码的目录,可选,分号分隔
  • -classfilters:<(+ | - )filter> [; <(+ | - )filter>] [; <(+ | - )filter>] - 报表中应包含或排除的类列表,可选,通配符被允许。

  

如下图,为报告部分截图,包含语句覆盖和分支覆盖情况。点击相应的页面,会进入对应程序,可看到具体覆盖到哪一行代码。

  

代码覆盖详情,绿色表示完全覆盖,橙色表示该行代码还有分支未覆盖到,红色则未覆盖。

 

补充:

1、如果是测试Windows服务的覆盖率:

1)执行如下命令启动服务:

G:\Opencover所在路径\OpenCover.Console.exe -service:byname -target:安装好的服务名 -register:ym -output:H:\白盒测试保存路径\xxx\xxx.xml 

2)测试完毕后,正常关闭服务,则可收集覆盖数据。

https://github.com/OpenCover/opencover/wiki/Service-Support

 

FAQ:

1)若提示

  原因有三: (1)未走到相关代码

        (2)缺少对应的pdb文件

        (3)未正确注册Profiler,添加参数-register:账号名

 

参考资料:https://www.cnblogs.com/tylerzhou/p/9076537.html

     https://www.cnblogs.com/SivilTaram/p/vs_opencover_unit_coverage.html