【问题标题】:Code coverage with optimization优化的代码覆盖率
【发布时间】:2016-08-24 03:14:24
【问题描述】:

目前我的 C++ 项目有一堆单元测试,但我还没有(还)测试代码覆盖率。我正在使用-O3 优化标志编译测试以暴露潜在的细微错误,但似乎如果我想使用gcov 之类的工具收集覆盖信息,则必须禁用任何优化标志。我是否应该构建两次测试(一次使用-O3,另一次没有)?这个问题一般是怎么处理的?

【问题讨论】:

  • How is this problem usually dealt with? 我正在用-O0 编译测试。使用 Valgrind(或 gcc 的一些 sanitize 标志)之类的分析器更适合查找潜在的错误。 -O3 适用于性能基准测试。
  • @Gluttton 是的,我正在使用 Valgrind 运行我的测试。 -O0 和没有优化标志一样吗?因为它是默认选项。
  • Is -O0 just the same as no optimization flags? 是的。

标签: c++ unit-testing code-coverage


【解决方案1】:

为了确保软件的质量,通常需要执行多种测试,并且针对哪些编译器选项有不同的标准。

通常,构建系统提供两种或多种构建选择,例如:

调试:-O0(无优化)带断言

发布:“更高的优化”(-O2、-Os 或 -O3,具体取决于您的项目的“最佳”),没有断言。这通常是您将代码交付给客户的模式。

有时会有“Release+Asserts”,这样您仍然可以在运行时检查代码的正确性,同时获得一些性能表现。

我认为测试可以分为以下几类:

  1. 功能正确性(又名“阳性测试”)。这是您检查“代码在正常情况下正常工作”的地方。同时运行 Debug 和 Release。

  2. 阴性测试。检查错误条件是否正常工作 - 传递应该给出错误的垃圾值(“不存在的文件”应该给出 E_NO_SUCH_FILE)。通常是调试和发布。

  3. 压力测试 - 运行严苛的测试,以检查软件在您长时间运行时是否正常运行,有很多线程等。通常是调试模式 - 可能两者兼而有之。

  4. 覆盖范围。运行一组测试以确保您“覆盖所有路径”(通常具有“未覆盖”的程度,例如您应该覆盖 95% 的功能和 85% 的分支 - 因为某些条件可能极难实现无需手动检测代码 - 仅当磁盘已满或操作系统无法创建新进程时才会出现错误)。通常编译为 Debug。

  5. 容错测试。一种“负面测试”形式,您可以在其中为内存分配和类似功能插入“模拟”功能,按顺序或随机模拟故障,以发现未检测到错误且代码因以下原因而失败的情况较早的错误,而不是在正确的位置产生正确的错误。同样,通常使用 Debug 运行 - 但也可能值得在 Release 中运行。

  6. 性能测试。在哪里测量程序的性能 - 每秒生成的帧数、编译器中的每秒行数或文件下载系统中的每小时千兆字节数等。这应该根据版本进行编译,因为“未优化”代码中的运行性能是几乎总是毫无意义。

对于复杂的软件产品,您通常需要在“运行所有内容”和“所需时间”之间做出妥协——例如,在调试和发布模式下运行所有​​ 4000 项功能测试可能需要 12 小时,而仅运行调试模式需要7小时,最好。这种妥协是通常的“工程决策”——“在理想世界中,你会这样做,但在现实世界中,我们必须妥协,这就是为什么我认为这种测试配置是正确的”。

例如,许多测试系统对源代码的每次更改都进行轻度测试(在工程师本人“我认为这可行”之后),每晚进行较重的测试,并在周末进行更多测试。这允许在运行所有测试所需的时间和一名工程师进行小改动所需的时间之间进行折衷。

【讨论】:

  • 如你在4中所说,-O0应该用于覆盖测试。对吗?
  • 是的,这经常发生,但并非总是如此。特别是如果您有 #if DEBUG 正在调用函数来检查事物,关闭调试将给出不同的覆盖结果。另一方面,根据覆盖工具的好坏[它与编译器交互的好坏],它可能无法“看到”来自内联函数的覆盖,因此完全优化的覆盖也可能无法正常工作。其中一部分取决于您尝试使用覆盖工具实现的目标 - 测试代码的生产版本,或检查测试是否涵盖所有分支等......
猜你喜欢
  • 2012-06-30
  • 2018-01-11
  • 1970-01-01
  • 1970-01-01
  • 2017-08-17
  • 2016-11-29
  • 2017-05-03
  • 2012-05-04
  • 2018-07-10
相关资源
最近更新 更多