C/C++test执行单元测试后,可以统计函数、语句、分支以及条件等不同层级的代码覆盖情况。很多人第一次看覆盖率时,会发现测试明明全部执行成功,报告里的覆盖率却比预想低,甚至部分源文件没有数据。这里通常要分清两件事:一是测试时到底插桩了哪些源码,二是当前查看的是哪一种覆盖率。覆盖范围没选全、使用了File Scope配置、测试路径没跑到,都会让最终统计结果看起来“不完整”。
一、C/C++test怎么设置代码覆盖率
1、使用单元测试配置采集覆盖率
如果已经创建好C/C++test测试工程,可以直接从单元测试配置开始。
①在【Project Explorer】中选中要测试的工程、目录或者源文件。
②打开【Parasoft】→【Test Using】。
③展开【Built-in】→【Unit Testing】。
④如果希望统计整个工程,选择【Run Unit Tests】。
⑤如果只想测试当前选中的文件,可以使用【File Scope】→【Run Unit Tests】。
⑥等待测试可执行程序完成构建和执行。
⑦执行结束后打开【Parasoft】→【Show View】→【Coverage】查看结果。
这里有一个很容易踩的坑:【File Scope】只会对选中的文件做插桩;普通【Run Unit Tests】则会对工程文件做更完整的插桩。如果想统计整个项目,却用了File Scope配置,其他文件没有覆盖数据并不奇怪。
2、切换需要查看的覆盖率类型
覆盖率不是只有一个百分比。C/C++test可以查看多种指标,包括函数、行、语句、基本块、分支、简单条件和MC/DC等。
①打开【Coverage】视图。
②点击Coverage视图右上角的下拉菜单。
③进入【Type】。
④按测试要求切换到【Line Coverage】【Statement Coverage】【Decision Coverage】或【MC/DC Coverage】等指标。
⑤展开工程,再展开源文件和函数,查看每一级的覆盖情况。
⑥双击某个函数,可以直接在源码编辑器中查看覆盖位置。
已覆盖代码和未覆盖代码会使用不同高亮显示,比单看一个百分比更容易找出遗漏路径。
如果测试报告需要给出详细源码级覆盖信息,可以打开对应【Test Configuration】,进入【Execution】→【Runtime】,设置【Generate detailed coverage report for】对应的覆盖指标。较新的Professional版本把详细覆盖报告设置放在测试配置里。
3、应用程序测试使用Coverage Monitoring
有些项目不是通过C/C++test生成的单元测试跑代码,而是希望程序正常运行时采集覆盖数据,这种情况可以用Application Monitoring。
①选中待测试工程。
②打开【Parasoft】→【Test Using】。
③进入【Built-in】→【Application Monitoring】。
④只采集覆盖率时,可选择【Build Application with Coverage Monitoring】。
⑤希望构建后直接运行,可以选择【Build and Run Application with Coverage Monitoring】。
⑥运行程序,把准备验证的功能路径完整操作一遍。
⑦程序结束后加载覆盖数据,再到【Coverage】视图检查结果。
Application Monitoring使用的是实际程序运行路径,所以哪些功能没有被操作到,哪些代码就不会产生覆盖记录。
二、C/C++test代码覆盖率统计不完整如何处理
1、先检查是不是只插桩了部分文件
整个工程有几十个源文件,Coverage里却只有几项,先看测试时选了什么配置。
①打开之前执行的【Test Configuration】。
②确认有没有使用【File Scope】配置。
③回到【Project Explorer】,直接选中工程根节点。
④重新执行【Built-in】→【Unit Testing】→【Run Unit Tests】。
⑤测试结束后重新展开【Coverage】。
⑥对照原来的结果,看缺失文件是否已经出现。
如果命令行运行C/C++test,还要检查有没有设置【-include】和【-exclude】。例如排除了某个目录,该目录自然不会进入本次测试范围。C/C++test的命令行支持通过include、exclude模式限制测试资源。
2、覆盖率有数据但百分比明显偏低
这时通常不是统计漏了,而是真的还有代码没有执行。
①打开【Coverage】视图。
②切换到当前要求的覆盖类型。
③展开覆盖率较低的源文件。
④继续展开具体函数。
⑤双击函数,在源码中找到未覆盖位置。
⑥回到【Test Case Explorer】,补充对应测试输入。
⑦重新运行【Run Unit Tests】。
例如下面这种逻辑:
现有测试只覆盖了speed小于100的情况,语句或分支覆盖就不可能完整。要补一组能够让条件成立的测试数据。
3、Line Coverage很高但MC/DC一直上不去
这类结果不能按“代码已经跑过”来判断。
假设判断条件是:
要提高【MC/DC Coverage】,不能只让整个表达式分别得到一次true和false。a、b、c每个条件都要通过合适的测试组合,证明它能够独立影响最终判断结果。因此,同一行代码已经执行过很多次,MC/DC仍然可能很低。
排查时可以这样做:
①在【Coverage】中切换为【MC/DC Coverage】。
②展开对应函数。
③找到未覆盖的条件。
④查看已有测试数据组合。
⑤补充能够单独改变该条件结果的测试用例。
⑥重新执行并查看覆盖变化。
三、覆盖率仍有缺失怎么继续排查
1、检查Coverage视图显示的指标和缓存结果
测试执行完成却显示空白,先别急着重新生成测试。
①打开【Coverage】。
②检查【Type】当前选择的覆盖类型。
③换到【Line Coverage】或【Statement Coverage】再看一次。
④展开工程节点,让Coverage视图刷新文件级数据。
⑤源码在IDE外部修改过时,先执行【Refresh】,再重新跑测试。
C/C++test在没有启用对应覆盖数据,或者Coverage视图选了另一种指标时,都可能出现没有数据显示的情况。
2、检查头文件和模板代码
头文件没有单独出现在覆盖结果里,不一定是遗漏。
①确认该头文件是否被待测.c或.cpp文件实际包含。
②检查头文件里的inline函数是否真的被调用。
③C++模板代码要确认模板已经实例化。
④重新查看包含它的源文件和对应函数。
C/C++test不会把一个完全没有被源文件包含的头文件当成独立测试对象;模板代码也要实际实例化后才会进入对应测试和覆盖范围。
3、检查测试是否提前结束
覆盖数据依赖测试程序正常执行和结果写出。如果测试可执行程序中途崩溃、abort,或者目标程序没有完成结果回传,就可能只拿到前半段数据。
①查看【Console】里的测试执行日志。
②检查有没有【crash】【abort】【timeout】一类错误。
③打开测试结果,确认是不是部分用例根本没有执行。
④先单独运行容易导致退出的测试用例。
⑤对会主动结束程序的函数使用桩函数隔离,或者修改测试环境。
⑥确认所有计划用例都执行结束后,再重新生成覆盖报告。
嵌入式目标、模拟器和远程测试环境更容易碰到这类问题,因为覆盖数据还涉及目标端结果回传。部分平台在测试程序提前终止时,只能保留退出前已经采集到的数据。
总结
C/C++test代码覆盖率统计是否完整,既和测试用例有没有真正走到目标代码有关,也受测试范围、插桩方式和覆盖指标影响。出现文件缺失或者百分比偏低时,先分清是“没有被统计”还是“确实没有覆盖”,后面的排查会简单很多。对于分支和MC/DC这类覆盖指标,还要专门补足不同逻辑组合,不能只靠增加普通测试次数。如需进一步了解C/C++test单元测试、代码覆盖率与测试结果排查方法,欢迎联系咨询。