zoukankan      html  css  js  c++  java
  • C#代码覆盖率实践-vsinstr和OpenCover

     

    C#代码覆盖率实践-vsinstr和OpenCover

    标签: C#覆盖率Visual StudioOpenCover测试
     分类:
    最近接触的项目涉及到C#开发的应用,测试过程中我们需要去分析C#的代码覆盖率,问了一些人,在网上也搜了一些,零碎的找到很多资料,但是都不是很完整,实际使用的过程中还是走了不少弯路。到现在为止,有两种可行的方案试验成功了,这里写出来给大家分享下。可能很多人都用过,就当是个整理吧。
     
    方法一:使用VS自带的vsinstr工具
    准备条件:安装VS2010或者VS2012。
     
    基本的操作步骤,主要是三个。
    1. 对被测的DLL进行插桩。
    "C:Program Files (x86)Microsoft Visual Studio 10.0Team ToolsPerformance Toolsx64vsinstr"  -coverage "D:xxx.dll"
    原来的dll自动被更名为 *.orig,相当于是一个备份。可以看到被插桩的DLL尺寸有所增加。

    2. 启动coverage数据监控和收集。
    start vsperfmon -coverage -output:"D:xyz.coverage" /CS /user:everyone


    3. 运行被测的程序,或者等待被执行。

    4. 停掉被执行的程序,可以直接关闭应用。
     
    5.  停止coverage监听,生成数据。
    vsperfcmd /shutdown
     
    6. 找到D:xyz.coverage,双击可以直接用VS打开查看。 显示的是block覆盖率,如果有source code可以对着代码查看。
     
    方法一小结:
    1. 这种方式除了最后查看报告,不需要启动VS,也不限制被测的代码如何被测试,可以手工也可以其他自动化程序。
    2. 目前来看需要逐个DLL插桩,对于exe文件没有尝试。
    3. 生成的覆盖率报告是二进制文件,需要在VS里面查看。
    4. 目前看到的是只有block级别的覆盖率数据,没有找到line级别的。
     
    方法二:使用免费的OpenCover工具
     
    准备条件:
    1. 安装OpenCover工具,可以直接下载msi或者zip包
    http://opencover.codeplex.com/wikipage?title=https%3a%2f%2fgithub.com%2fopencover%2fopencover%2freleases
     
    2. 下载ReportGenerator工具,用于将OpenCover生成的XML报告转换成更加可读的HTML报告。
     
    具体的步骤:
    1. 在VS里面随便用C#写了一小段代码,包含了一个分支,用于查看覆盖和未覆盖的情况。编译成 ConsoleApplicaiton1.exe
     
    2. 通过OpenCover将被测的ConsoleApplicaiton1.exe在命令行启动起来,加上相关的参数。
     -output:c2.xml   指明将生成的报告文件名。
    -targetdir:  告诉OpenCover这个exe对应的PDB在哪儿。两种方法PDB文件都是必须的。
    -register 不是很清楚用途,但是是必须的,第一次没加这个参数覆盖率数据出不来。
    更详细的参数请查看OpenCover的手册。
     
    具体的命令:
    OpenCover.Console.exe -register -target:"C:Users ickyqiuDocumentsVisual Studio 2012ProjectsConsoleApplication1ConsoleApplication1inDebugConsoleApplication1.exe" -output:c2.xml -targetdir:"C:Users ickyqiuDocumentsVisual Studio 2012ProjectsConsoleApplication1ConsoleApplication1inDebug"
     
    执行的结果如下面的cmd窗口。程序很简单,所以很快跑完了,显示了一个覆盖率的摘要。
     
    这样就可以得到指定的报告文件 c2.xml了。
     
    3. 可以用ReportGenerator工具生成HTML的报告便于查看。
     
    由于这里有源码,所以HTML报告里面就直接显示了代码行级别的覆盖率。红色的部分是没有执行到的,绿色的是被执行到的。加起来是可覆盖(coverable)行。这里的概念都是比较通用的,和其他语言的覆盖率也是一样的。
     
    方法二小结:
    1.  这个方法没有显示的插桩(instrument)的动作,我的理解是在将被测程序启动的时候做了一些事情。试过多个文件包含exe和dll都是可以的。
    下面是一个外面找到的实际的大一点的子项目代码的例子。
     
    2. 可以直接看到line级别的覆盖率数据,有源码的话可以直接映射到源码,无源码是到文件级别的汇总数据。
     
    3. 整个使用过程还是非常方便的,无论是上面的demo console小程序,还是这个有GUI的比较大的实际client。被启动后可以像单独运行时一样使用,无任何感知,所以对测试手段也没有要求,手工或者自己的自动化程序都可以。
     
    4. 报告比较方便,特别是用ReportGenerator后。
     
     
    还有一些待研究的:
    1. 如果团队有多人一起执行测试,如何合并多人的覆盖率数据。
    2. 如果是对于server端的程序,如何来处理。应该是可以做到,但是需要去验证。
     
    总的来说,无论那种方法提供的数据,对于我们的测试都有很好的参考价值,是一个重要的辅助手段。
     
     

    在单元测试实践中经常会需要查看代码覆盖率,大多生成单元测试覆盖率的软件都是收费的。

    开源的Coverage Tool不多,OpenCover是一个不错的选择。

    参考:http://stackoverflow.com/questions/276829/code-coverage-for-c-net

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

    1. 准备工具

    NUnit或者MS Unit

    OpenCover:从这里获取

    ReportGenerator:https://github.com/danielpalme/ReportGenerator

    你也可以从nuGet上获取,具体方法请自己百度

    2. 配置环境

    OpenCover使用起来并不复杂,只是配置路径有点麻烦。

    运行OpenCover需要一系列参数,这里只说明几个主要的参数:

    -target:这是目标应用或服务的路径(名称),这里指单元测试工具的路径,支持NUnit和MS Unit

    -targetdir:目标目录的路径,如果target argument已经包含了一个路径,那么这个参数可以提供一个查找pdb文件的可选路径

    -targetargs:target参数指定的应用所需要的参数(编译测试工程生成的一个dll文件或者EXE文件路径)

    -output:输出XML文件的路径,如果没有提供将在当前目录下生成results.xml, 该文件将用于ReportGenerator生成可视化的覆盖率报告

    ReportGenerator所需要的参数:

    -reports:上述XML文件的路径

    -targetdir:生成报告的目录

    为了方便环境配置,本人采用了Python脚本跟ini配置文件的方式

    下面是脚本程序跟配置文件,请根据项目实际情况配置路径:

    [python] view plain copy
     
    1. # run.py 只需执行这个脚本就可以生成可视化报告  
    2. import configparser  
    3. import os  
    4.   
    5. config = configparser.ConfigParser()  
    6.   
    7. try:  
    8.     config.read('config.ini')  
    9.   
    10.     if 'Default' in config.sections():  
    11.         if 'opencoverpath' in config['Default'].keys():  
    12.             OpenCoverPath =  config['Default']['opencoverpath']  
    13.         if 'nunitpath' in config['Default'].keys():  
    14.             NUnitPath = config['Default']['nunitpath']  
    15.         if 'projdir' in config['Default'].keys():  
    16.             ProjDir = config['Default']['projdir']  
    17.         if 'projpath' in config['Default'].keys():  
    18.             ProjPath = config['Default']['projpath']  
    19.         if 'outpath' in config['Default'].keys():  
    20.             OutPath = config['Default']['outpath']  
    21.         if 'reportgenpath' in config['Default'].keys():  
    22.             ReportGenPath = config['Default']['ReportGenPath']  
    23.         if 'reporttargetdir' in config['Default'].keys():  
    24.             ReportTargetDir = config['Default']['ReportTargetDir']  
    25.         # print(OpenCoverPath)   
    26.         # print(NUnitPath)   
    27.         # print(ProjDir))  
    28.         # print(ProjPath)  
    29.         # print(OutPath)  
    30.         os.system('{0} -register:user -target:{1} -targetdir:{2} -targetargs:{3} -output:{4}'.format(OpenCoverPath, NUnitPath, ProjDir, ProjPath, OutPath))  
    31. except e:  
    32.     print(e.message)  
    33. else:  
    34.     os.system('{0} -reports:{1} -targetdir:{2}'.format(ReportGenPath, OutPath, ReportTargetDir))  
    [python] view plain copy
     
    1. [Default]  
    2. OpenCoverPath = D:ReportsToolsOpenCoverOpenCover.Console.exe  
    3. NUnitPath = D:ProjpackagesNUnit.Runners.2.6.4 ools unit-console-x86.exe  
    4. ProjPath = D:ProjUnitTestProjinDebugUnitTestProj.exe  
    5. ProjDir = D:ProjUnitTestProjinDebug  
    6. OutPath = D:ReportsNUnitTestcoverage.xml  
    7. ReportGenPath = D:ReportsToolsReportGeneratorinReportGenerator.exe  
    8. ReportTargetDir = D:ReportsCodeCoverage  

    注:一种简单的可选方案是直接将命令保存在文本文件里,需要运行时直接拷贝到命令窗口执行

    3. 生成报告

    运行上述run.py脚本即可,感受下:

  • 相关阅读:
    字符串数组
    常用函数
    判断是否是素数回文数
    杨辉三角
    惨痛的教训 没有 脑子的我
    剪缎带
    ?????函数不起作用
    C#3
    celery 原理和组件
    vue检查用户名是否重复
  • 原文地址:https://www.cnblogs.com/liangqihui/p/7275655.html
Copyright © 2011-2022 走看看