很多人一提到C/C++test覆盖率,第一反应就是把测试跑起来再看百分比,但真正决定结果能不能采上来、性能会不会被拖慢的,往往不是“跑没跑”,而是你前面选了哪条采集链路、哪种插桩模式。Parasoft官方把覆盖率采集分成两大类,一类是单元测试执行时直接采,一类是把应用先做成带插桩版本,再在手工测试、功能测试或系统测试过程中回收覆盖数据;两类路径都能看覆盖率,但适用场景和开销并不一样。
一、C/C++test覆盖率怎么采
覆盖率怎么采,先别急着盯报表,第一步应该先看你现在做的是单元测试,还是整机、功能或系统级测试。因为C/C++test官方本来就支持这两条采集路径,而且入口完全不同,场景选错了,后面再调参数也容易别扭。
1、做单元测试时,直接在Test Configuration里开覆盖率
如果你现在主要是在IDE里跑单元测试,最直接的做法就是到【Parasoft】【Test Configurations】里打开对应配置,再到【Execution】页签里确认插桩和覆盖率选项已经启用。官方说明里写得很清楚,覆盖率是否采集,本质上由【Execution】里的instrumentation设置决定;跑完以后再到【Coverage】视图切换查看line、function、decision、basic block、path、simple condition或MC/DC等指标。
2、做应用级覆盖率时,用Application Monitoring这条线
如果你不是跑单元测试,而是想看应用在手工测试、功能测试或系统测试里的真实覆盖情况,就更适合走Application Monitoring。Parasoft官方对它的定义很明确,这是一种面向实际应用运行的监控方式,插桩相对轻量,适合在目标板、模拟器或主机上做应用级覆盖率采集。
3、想把覆盖率纳入构建流程时,用cpptestcc
如果你的目标不是在IDE里临时看一次,而是把覆盖率采集正式接进构建系统、CMake或CI,官方更推荐cpptestcc这条线。它的流程分三步,先把cpptestcc接进构建命令做插桩,再运行应用或测试收集原始覆盖数据,最后把生成的.clog数据导回C/C++test生成报告;CMake也有现成的覆盖扩展可直接接入。
4、先把覆盖率类型收窄,再去跑
C/C++test能报的覆盖率种类很多,官方列出的常见指标包括function、line、path、basic block、decision、simple condition和MC/DC,cpptestcc这边还支持call coverage。真正落地时,没必要一开始就全开,日常回归通常先看line或function就够,流程准入或安全合规场景再逐步加到decision、simple condition或MC/DC,会更稳。这个选择本身是基于官方支持的指标范围和不同指标的开销差异做出的实践判断。
二、C/C++test插桩方式怎么选择
插桩方式怎么选,关键不是哪个名字更高级,而是你当前更在意能力完整、执行速度,还是目标环境承受能力。Parasoft在【Execution】页签里把常见模式已经预置好了,从Full到Application coverage monitoring,再到No instrumentation和Custom instrumentation,实际上就是在帮你按场景做取舍。
1、单元测试要功能齐全,先用Full
如果你现在的重点是单元测试,而且还会用到桩、堆栈回溯、访问私有成员,或者被测代码里带有main,这时候最稳妥的是先用Full。官方对Full的描述很清楚,它包含覆盖率、function stubs、stack trace reporting、access to private members和rename main等完整能力,适合先把测试链路跑通。
2、只想看行覆盖率,优先用Full runtime with line coverage
有些项目只是想确认单元测试大概扫到了哪些行,不打算一开始就把所有覆盖率类型都加上。这种情况下,官方预置的Full runtime with line coverage更省事,因为它保留完整运行时插桩框架,但把覆盖率收窄到line coverage,而且line hit count默认也关掉,整体更轻一些。
3、做应用级测试,优先选Application coverage monitoring
如果你跑的是整应用,不是单元测试,那么Application coverage monitoring会比Full更合适。官方把它定义为对完整应用做覆盖率跟踪的模式,而Application full monitoring则是在同一轮里同时做运行时错误检测和覆盖率跟踪;如果目标板内存紧,官方还明确提醒,覆盖率和内存监控未必适合同开,这时更适合分开跑。
4、性能特别敏感时,再考虑optimized模式
Parasoft官方把optimized coverage metrics说得很明确,这种模式是专门给application level testing准备的,不适用于unit testing。它的核心思路是把覆盖数据先放进内存缓冲区,等应用结束或用户手动请求时再统一写出,因此执行时开销更低;代价是如果应用崩溃,尚未刷出的数据可能丢失。也就是说,性能敏感、时序敏感的应用级测试更适合它,容易崩溃或你特别在意崩溃前数据完整性的场景,则更适合默认的即时上报模式。
5、需要精细取舍时,最后再用Custom instrumentation
如果预置模式都不够贴,你再去用Custom instrumentation。官方在自定义项里给出的可控点很多,包括C/C++Code Coverage、Stack trace reporting、Access to private members、Function stubs、Rename main、Memory monitoring和Assembly Code Coverage;另外还可以单独指定覆盖率指标、是否统计line hit count,以及是否打开C++templates的覆盖率。也就是说,Custom更适合已经知道自己要保留什么、删掉什么的项目,不适合作为第一步。
三、C/C++test覆盖采集先走哪条路
很多团队卡住,不是因为不会开覆盖率,而是每个项目都用同一套插桩思路,结果不是太重,就是太散。更稳的办法,是按项目类型先选路线,再回头细调指标和开销。这个判断虽然带有实践经验色彩,但完全是顺着官方提供的三条能力边界来的。
1、日常开发回归,先走单元测试内置覆盖率
如果是研发自测、模块回归、接口级检查,直接在单元测试配置里开覆盖率最省事。因为这条链路和断言、桩、测试结果本来就在一起,覆盖率只是顺带采出来,适合开发日常快速看结果。
2、系统测试和手工测试,优先走Application Monitoring或cpptestcc
如果测试行为主要发生在应用运行阶段,而不是测试框架内部,那么覆盖率就更应该跟着应用走。要在IDE里本地观察,可以偏向Application Monitoring;要跟构建系统、CMake或外部测试平台打通,则更适合cpptestcc,因为它本来就是为把插桩接进构建流程、导出.clog再生成报告设计的。
3、目标环境资源紧,先减指标,再换optimized
嵌入式或板级环境最容易一上来就把模式开重。官方给出的建议其实已经很清楚了,默认即时上报模式结果更稳,optimized模式更省执行时间,但要额外处理初始化和收尾,而且更怕崩溃丢数。更实际的顺序通常是先把覆盖率指标从line、function这种基础指标收窄,再评估是否要切optimized,而不是一开始就追求所有高级指标全开。
4、报表没数据显示,先回头查两件事
官方在覆盖率查看文档里专门提醒过,如果跑完没有覆盖数据,先查两点,一是覆盖率有没有真正启用,二是当前【Coverage】视图显示的指标类型,是不是和你实际配置采集的类型一致。很多看起来像“插桩没生效”的情况,最后其实只是这两步没对上。
总结
C/C++test覆盖率怎么采,核心不是只看报表,而是先分清你做的是单元测试覆盖率、应用级覆盖率,还是要接进构建系统的独立覆盖率链路。C/C++test插桩方式怎么选择,关键也不是默认开到最重,而是按场景去选Full、Full runtime with line coverage、Application coverage monitoring、optimized coverage或Custom instrumentation。单元测试优先走内置执行链路,应用级测试优先走Application Monitoring,构建集成优先看cpptestcc;先把路径选对,再去调指标和开销,覆盖率结果通常会稳很多。