带优化的代码覆盖率
Code coverage with optimization
目前我有一堆针对我的 C++ 项目的单元测试,但我(还)没有测试代码覆盖率。我正在使用 -O3
优化标志编译测试以暴露潜在的细微错误,但似乎如果我想使用 gcov
等工具收集覆盖率信息,则必须禁用任何优化标志。我是否应该构建测试两次(一次使用 -O3
,另一次不使用)?这个问题一般是怎么处理的?
通常要执行多种测试来确保软件的质量,以及不同的编译器选项标准。
通常,构建系统会提供两种或多种构建选择,例如:
调试:-O0(无优化)带断言
Release: "higher optimisation"(-O2、-Os 或 -O3 取决于项目的 "best")没有断言.这通常是您将代码交付给客户的模式。
有时 "Release+Asserts" 这样您仍然可以检查代码的正确性,同时 运行 有一些表面上的性能。
以下是我认为测试可以分为的一些类别:
功能正确性(又名 "positive tests")。这是您检查 "the code works correctly under normal circumstances" 的地方。 运行 调试和发布。
阴性测试。检查错误条件是否正常工作 - 传递应该给出错误的垃圾值("file that doesn't exist" 应该给出 E_NO_SUCH_FILE)。通常调试和发布。
压力测试 - 运行宁严酷的测试,检查软件在你 运行 长时间运行时是否正确运行,有很多线程等等。通常调试模式 - 可能两者都有。
覆盖范围。 运行 一组测试以确保您 "cover all paths"(通常具有 "not covered" 的程度,例如您应该覆盖 95% 的功能和 85% 的分支 - 因为某些情况可能在不手动检测代码的情况下很难实现——只有当磁盘完全满时或 OS 无法创建新进程时才会出现错误)。通常编译为 Debug.
容错测试。 "negative tests" 的一种形式,您可以在其中为内存分配和类似功能插入 "mock" 功能,模拟顺序或随机失败,以发现未检测到错误且代码失败的情况,如下所示 -基于早期错误的结果,而不是在正确的地方产生正确的错误。同样,通常 运行 与 Debug - 但在 Release 中也可能值得 运行ning。
性能测试。衡量程序性能的地方 - 每秒生成的帧数、编译器中的每秒行数或文件下载系统中的每小时千兆字节数等。这应该根据发行版进行编译,因为 运行ning 在 "not optimised" 代码几乎总是毫无意义。
对于复杂的软件产品,您通常需要在 "running everything" 和 "the time it takes" 之间进行折衷 - 例如,运行在调试和发布模式下进行所有 4000 项功能测试可能需要 12小时,运行仅调试模式需要 7 小时,所以更可取。这种妥协是通常的 "engineering decision" - "In an ideal world, you'd do this, but in the real world, we have to compromise, and here's why I think this configuration of tests is right"。
许多测试系统在 "I think this works" 工程师 him/herself 之后 运行 对源代码的每个更改进行轻度测试,每晚进行更重的测试,并在例如,一个周末。这允许在 运行 所有测试所需的时间和一名工程师进行小更改所需的时间之间进行折衷。
目前我有一堆针对我的 C++ 项目的单元测试,但我(还)没有测试代码覆盖率。我正在使用 -O3
优化标志编译测试以暴露潜在的细微错误,但似乎如果我想使用 gcov
等工具收集覆盖率信息,则必须禁用任何优化标志。我是否应该构建测试两次(一次使用 -O3
,另一次不使用)?这个问题一般是怎么处理的?
通常要执行多种测试来确保软件的质量,以及不同的编译器选项标准。
通常,构建系统会提供两种或多种构建选择,例如:
调试:-O0(无优化)带断言
Release: "higher optimisation"(-O2、-Os 或 -O3 取决于项目的 "best")没有断言.这通常是您将代码交付给客户的模式。
有时 "Release+Asserts" 这样您仍然可以检查代码的正确性,同时 运行 有一些表面上的性能。
以下是我认为测试可以分为的一些类别:
功能正确性(又名 "positive tests")。这是您检查 "the code works correctly under normal circumstances" 的地方。 运行 调试和发布。
阴性测试。检查错误条件是否正常工作 - 传递应该给出错误的垃圾值("file that doesn't exist" 应该给出 E_NO_SUCH_FILE)。通常调试和发布。
压力测试 - 运行宁严酷的测试,检查软件在你 运行 长时间运行时是否正确运行,有很多线程等等。通常调试模式 - 可能两者都有。
覆盖范围。 运行 一组测试以确保您 "cover all paths"(通常具有 "not covered" 的程度,例如您应该覆盖 95% 的功能和 85% 的分支 - 因为某些情况可能在不手动检测代码的情况下很难实现——只有当磁盘完全满时或 OS 无法创建新进程时才会出现错误)。通常编译为 Debug.
容错测试。 "negative tests" 的一种形式,您可以在其中为内存分配和类似功能插入 "mock" 功能,模拟顺序或随机失败,以发现未检测到错误且代码失败的情况,如下所示 -基于早期错误的结果,而不是在正确的地方产生正确的错误。同样,通常 运行 与 Debug - 但在 Release 中也可能值得 运行ning。
性能测试。衡量程序性能的地方 - 每秒生成的帧数、编译器中的每秒行数或文件下载系统中的每小时千兆字节数等。这应该根据发行版进行编译,因为 运行ning 在 "not optimised" 代码几乎总是毫无意义。
对于复杂的软件产品,您通常需要在 "running everything" 和 "the time it takes" 之间进行折衷 - 例如,运行在调试和发布模式下进行所有 4000 项功能测试可能需要 12小时,运行仅调试模式需要 7 小时,所以更可取。这种妥协是通常的 "engineering decision" - "In an ideal world, you'd do this, but in the real world, we have to compromise, and here's why I think this configuration of tests is right"。
许多测试系统在 "I think this works" 工程师 him/herself 之后 运行 对源代码的每个更改进行轻度测试,每晚进行更重的测试,并在例如,一个周末。这允许在 运行 所有测试所需的时间和一名工程师进行小更改所需的时间之间进行折衷。