章节目录:
静态代码分析
C++test 通过静态分析代码来执行静态代码分析,以检查是否符合指定的静态代码分析规则。该分析旨在通过以下方式避免错误并提高代码质量:
- 检测源中的明确或潜在缺陷。
- 避免使用可能危及安全性的代码
- 实施组织设计指南和规范(特定于应用程序、用途或平台)以及从已知特定错误中抽象出来的错误预防指南。
- 通过改进类设计和代码组织结构来提高代码的可维护性。
- 通过应用通用格式、命名和其他风格约定来增强代码的可读性。
C++test 预先配置为使用内建规则集执行静态代码分析。大多数静态代码分析检查测试配置中默认启用的规则,经证明可以立即且显著地优化代码。遵循这一系列核心准则的代码将更高效、更安全、更易于维护,并且遇到功能问题的可能性更低。
除了提供预配置的规则集,C++test 还允许您定义自己的规则集,包括自定义规则,从而实现您的团队专属的编码策略。为方便团队确定要遵的规则,这些规则按主题(例如,安全性、优化、初始化等)进行分类,并按严重性(检测到的问题将导致 bug 的可能性)进行排序。
如需了解有关 C++test 中包含的静态代码分析规则的更多信息,请选择 Parasoft> 帮助,打开 C++test Static Analysis Rules 手册,然后浏览可用的规则描述文件。
C++test 还可以检查您用 RuleWizard 模块设计的任意数量的自定义规则。使用 RuleWizard,可以图形化创建规则(通过创建类似于流程图的规则表示形式),也可以自动创建规则(通过提供演示违规示例的代码)。通过创建和检查自定义规则,团队可以验证独特的项目和组织需求,并防止最常见的错误再次发生。
有关执行静态代码分析的详细信息,请参阅静态代码分析。
抑制
抑制用于防止 C++test 报告特定静态分析任务的额外出现(单个规则可能会报告多个任务)。当您希望遵循某个规则但想在少数例外情况下忽略该规则时,您可以对这些特殊情况采用抑制。通过抑制,您可以继续检查代码是否遵循该规则,而不会收到关于例外违规的重复消息。如果不想接收任何违反特定规则的错误消息,我们建议您修改您的测试配置,这样就不会再检查该规则。
抑制可以存储在源代码或本地抑制文件中,这些文件可以签入源码控制系统,以便在整个团队中共享。
注意,抑制设置是独立于测试配置的。为了避免混淆,请记住:
- 测试配置定义了在静态分析期间检查的规则集。
- 抑制定义了哪些静态分析结果应该在质量任务视图和报告中可见。
这意味着在分析期间将检查测试配置中选择的规则,但是不显示与抑制条件匹配的结果。
有关创建抑制的详细信息,请参阅抑制对可接受违规的报告。
RuleWizard 图形规则编辑器
RuleWizard 允许您为 C/C++ 代码和格式问题创建自定义静态代码分析规则。C++test 可以自动执行在 RuleWizard 中创建的任何有效规则。通过创建和检查自定义规则,团队可以验证独特的项目和组织需求,并防止最常见的错误再次发生。
使用 RuleWizard,可以图形化创建规则(通过创建类似于流程图的规则图),也可以自动创建规则(通过提供规则违反示例的代码)。编写或修改规则不需要编写代码或了解解析器。
打开 RuleWizard 有两种方法:
- 选择 Parasoft> 启动 RuleWizard。
- 点击测试配置面板静态选项卡中的新建按钮。
将打开 RuleWizard 用户界面。RuleWizard 用户指南(可在 RuleWizard GUI 中选择帮助> 文档来访问)包含关于如何修改和保存自定义规则的信息。
有关创建和使用自定义规则的详细信息,请参阅自定义现有规则和创建新规则。
流分析
重要说明
使用此功能需要额外的许可证。请联系您的 Parasoft 代表。
流分析是一种新型静态分析技术,它使用多种分析技术,包括模拟应用程序执行路径,来识别可能触发运行时缺陷的路径。检测到的缺陷包括使用未初始化的内存、空指针解引用、被零除、内存和资源泄漏。
由于这种分析涉及识别和跟踪复杂的路径,它暴露了通常能逃避静态代码分析和单元测试的 bug,并且这些 bug 很难通过手动测试或检查发现。流分析在不执行代码的情况下暴露 bug 的能力对于拥有遗留代码库和嵌入式代码的用户而言尤其有效(运行时检测在这种情况下无法检测到此类错误)。
这种独特的静态分析通过搜索代码中的“可疑点”开始分析被测源代码。可疑点是指可能出现 bug 的点。这些可疑点在流分析规则中定义。每当发现可疑点时,流分析都会调查可能通向该点的执行路径,并检查这些路径中是否有任何一条实际违反了流分析规则。如果发现这样的路径,则报告违规。
例如,根据用于检测被零除错误的规则,任何使用“/”或“%”运算符的点都是可疑点。然后,它会检查通向该点的任何可能的执行路径中,分母的变量是否可能为零。如果是,则报告错误。
对于发现的每个 bug,分层流路径数据会精确且详细地描述导致已识别 bug 的完整执行路径,以 bug 出现的确切代码行结束。为了减少诊断和纠正发现的每个问题所需的时间和精力,流路径详细信息用大量注释来补充说明(例如,“避免空指针解引用”违规说明包含描述哪些变量在流路径中的哪个点包含空值的注释)。
为了使分析过程更加灵活,并根据您独特的项目需求进行定制,可以对一些规则进行参数化。因此,流分析甚至可以用于检测与极其特定的 API 使用相关的违规。
开发团队使用流分析主要可以获得以下优势:
- 利用现有资源进行更全面的测试:流分析通过让您能够发现原本需要开发、执行和维护复杂测试用例才能发现的问题来补充其他测试技术。流分析调查程序中的各种分支可能性,提供传统测试难以实现的路径覆盖率水平。因此,流分析通常能够识别在处理罕见情况时出现的问题,而这些情况通常在测试中未被覆盖。而且,如果代码功能发生变化,您可以在修改后的版本中搜索 bug,而无需更新或重新生成测试用例。
- 自动识别通过多个单元的 bug:传统的自动化单元测试生成可以帮助您识别单个编译单元中的 bug。这一点十分重要。然而,开发人员在执行了彻底的单元级测试,纠正了所有明显的问题以及集成了代码之后,如果遇到问题(如空指针解引用),这些问题则需要好几天时间来诊断,因为它们是由经过多个函数甚至多个编译单元的模糊或复杂的执行路径产生的。使用流分析则可以自动识别类似的问题
将重心放在实际的 bug 和设计缺陷上:流分析根据合理判断,自动识别数据相关或流相关的 bug。流分析报告违规通常是因为存在设计缺陷,具体表现为简单的违规,如被零除或资源泄漏。
例如,除非有一个方法调用 calculateBufferLength 并向其传递一个空指针,否则流分析不会报告以下代码的违规:
int calculateBufferLength(char* str) { return strlen(str) + 1; }
- 发现 API 滥用情况:实践中的许多 bug 是由于使用错误的参数调用了一些 API 或者没有正确处理 API 返回的值。例如,当参数 1 为 true 时,API 可能期望参数 2 为非空参数,或者 API 可能会将对象中的某个字段设置为空。通过执行过程间分析,流分析可以识别使用此类 API 时不一致问题。
详细信息请参阅流分析。
单元测试
“单元测试”是指在最简单的功能点测试软件代码,该功能点通常是一个类或函数。单元测试通常由开发人员在开发周期内而不是 QA 阶段执行。使用单元测试可以确保应用程序构建模块在集成之前的稳固状态,从而提高整个应用程序的质量。测试执行得早,识别和修复缺陷通常就不会过于困难和耗时。
手动单元测试通常包括手动编写自动化测试框架、指定输入数据以及为缺失的函数和变量提供桩函数。 C++test 将这些任务自动化,使单元测试过程更加高效和一致。
通常而言,单元测试包括:
- 异常测试(也称为白盒测试、压力测试、构造测试或可靠性测试),用于确认代码结构合理,并且可以处理所有可行的输入及其组合,而不会抛出意外的异常。
- 功能测试,用于验证软件构建模块是否符合其规范,以及是否包含了所有预期的功能并正常工作。在单元级别创建功能测试涉及指定特定输入和状态条件的人工输入,以及期望的输出。功能测试可以实现为白盒测试(基于对被测单元的内部和实现的了解进行测试)或黑装箱测试(仅基于被测单元的外部行为)。
- 回归测试,用于验证现有代码行为不会随着代码库的演进而改变。这通常需要开发一组测试,验证它们的正确性,并在代码更改后运行这些测试来捕捉代码行为中的偏差。回归测试可能依赖于异常测试和功能测试。
C++test 可以执行所有描述类型的单元测试,您可以根据您的需求和测试偏好自定义测试的级别和范围。
当您运行 C++test 自动生成的测试用例时会执行异常测试。这种类型的测试会暴露意外的异常,并检查类的结构是否合理。可靠性测试的成功取决于对代码的彻底覆盖,因此您可以根据需要继承自动生成的测试用例,以增加代码覆盖率。C++test 判断测试覆盖率,帮助您评估覆盖率并确定哪些地方需要进行额外测试。
当您对自动生成的测试用例进行继承以验证类的公共接口是否按照规范中的描述操作时就会执行功能测试。
回归测试包括通过运行所有可用的测试用例并检查期望的结果是否发生了变化来定期测试不断演变的代码库。在当前测试运行的测试用例结果与期望的测试用例结果不匹配时,C++test 会报告错误消息。
测试用例可以在 C 或 C++ 源代码中实现和保存。您可以在 IDE 的文本编辑器中继承和修改生成的测试用例。这些测试用例使用与主流 CppUnit 格式类似的格式。C++test 的测试提供了比 CppUnit 更广泛的功能,包括测试 C 代码的功能,并且提供对测试框架内私有和受保护数据和成员函数的编程访问。现有的 CppUnit 测试用例可以导入到 C++test 中,并与自动生成的测试用例一起使用。
有关执行单元测试的详细信息,请参阅测试创建和执行。
测试用例生成
编写单元测试是保证代码质量的一项重要任务。单元测试不仅可以暴露 bug 和功能问题,还可以作为常规回归测试运行,帮助您确定代码添加/修改是否破坏了现有功能或导致意外变更。
然而,编写测试非常耗时,如果不小心,可能还会忽略许多重要问题。C++test 提供的单元测试支持有助于开发人员和测试人员快速创建良好的单元测试。它会自动生成许多单元测试,并允许用户自定义测试生成和执行以满足特定偏好和需求。C++test 自动生成大量测试用例,这些测试用例尝试执行代码中的所有不同路径,然后保存实际的测试用例结果。这些测试用例本质上是对代码的当前状态进行 x 光检查,捕捉代码在修改之前的运行情况。它们还有助于识别可能影响代码可靠性和安全性的潜在异常。
C++test 可以生成从单个函数到整个项目的任何 C/C++ 代码的测试用例。通过在 C++test 中运行这些测试用例,您可以验证类健壮性并识别可能导致程序进入不一致状态或终止的输入。您可以自定义预配置的测试模式,以及特定的测试生成设置。
测试用例在 C 或 C++ 源代码中实现并保存(使用的语言取决于原始的被测源代码)。这些测试用例使用与主流 CppUnit 格式类似的格式。C++test 的测试提供了比 CppUnit 更广泛的功能,包括测试 C 代码的功能,并且提供对测试框架内私有和受保护数据和成员函数的编程访问。现有的 CppUnit 测试用例可以导入到 C++test 中,并与自动生成的测试用例一起使用。测试套件可以用用户定义的测试用例进行扩展,以提高测试覆盖率并验证特定的功能;这些测试可以通过修改自动生成的测试用例或定义新的测试用例来添加。任何可用的测试用例都可以自动验证并配置用于回归测试。通过保存所有可用的测试用例并利用它们进行自动化回归测试,您可以建立一个回归测试基础设施,该基础设施可以立即识别由代码修改引入的意外功能变更和异常。
自动化测试用例生成使您能够在更短的时间内创建更高效的测试套件。测试用例开发通常是单元测试过程中最耗时的部分。而有了自动化测试用例生成,您不需要编写任何代码来生成一组基本的测试用例来执行每个类,并且您可以通过向自动生成的测试用例添加少量代码来创建更多的测试用例。一般情况下,您不需要担心编写简单方法的测试用例,并且可以将资源集中在为更复杂的方法扩展/添加测试方面。
此外,测试用例生成有助于在以下两个关键方面预防错误:
- 在完成类的编写或修改后立即生成和执行测试用例。这有助于您(或团队成员)在无意间添加基于问题代码构建或与问题代码交互的代码而引入其他错误之前发现并修复问题。
- 通过自动生成所需范围和类型的测试用例来实现快速、彻底的可靠性测试,而手动设计这样的测试用例是不现实的。C++test 尝试创建的测试用例会执行其测试的每个方法的每个可能分支。例如,如果方法包含条件语句(如
if
代码块),C++test 将尝试生成测试用例,测试if
语句的true
和false
结果。
有关执行自动化测试用例生成的详细信息,请参阅生成用于回归测试和异常发现的测试用例。
桩函数
桩函数用作函数的替代实现,以便将测试与被测功能集之外的依赖项隔离。使用桩函数时,执行流会重定向到桩函数。
使用桩函数的两个主要原因:
- 将被测代码与集成环境隔离开来。
- 在无法影响函数的行为时进行测试,需要替代实现。
桩函数也可以用于 C++ 模板。详细信息请参阅使用 C++模板的桩函数。
您可以为任何测试用例定义自己的桩函数——自动生成的测试用例以及用户定义的测试用例。当您使用用户定义的桩函数时,您可以完全控制外部函数向被测类返回的值,而无需提供实际的外部函数。
如果用户定义的桩函数可用,它将始终在测试执行期间使用——即使原始函数可用。如果原始定义一开始不可用,但后来添加了,C++test 将继续使用用户定义的桩函数。如果您希望使用原始定义,则需要删除(或注释掉)桩函数。
用户定义的桩函数以函数定义的形式实现,函数名中带有“CppTest_Stub_”前缀。例如:
/* C++test user stub definition for int doSomething(int i) */ int ::CppTest_Stub_doSomething(int i) { return i + 10; }
桩函数的声明必须能够在桩函数文件中访问。在大多数情况下,这通过将正确的头文件包含到桩函数文件中来实现。
C++test 的桩函数(除了构造器桩函数)采用与原始函数相同的值。
使用桩函数向导自动生成或创建的桩函数可以从测试用例中动态配置,而不需要修改桩函数的主体。您可以在测试用例编辑器中动态配置桩函数(请参阅使用测试用例编辑器添加测试套件和测试用例)或使用动态桩函数配置直接从测试用例源代码配置(请参阅动态桩函数配置)。
如果使用动态桩函数配置还不够,您可以用自定义逻辑实现替换生成的桩函数的主体,并使用用户定义桩函数的 C++test API 函数(请参阅用于用户定义桩函数的 C++test API 函数)。
如需了解有关自动生成的桩函数的更多信息,请参阅了解和自定义自动化桩函数生成。
如需了解如何将用户定义的桩函数用于测试期间不能(或不想)访问的外部资源,请参阅添加和修改桩函数。
工厂函数
工厂函数是用户定义的方法,用于初始化给定类型的对象。当自动生成测试用例以及使用测试用例向导创建测试用例时,可以使用这些方法。
工厂函数可用于:
- 为用户定义的类型提供复杂的初始化器(通过编写一个在实际对象创建后执行额外初始化的工厂函数)。
- 减少可能的对象创建方法的数量(通过编写一个只使用特定类的可用构造函数之一的工厂函数)。
工厂函数是在函数名中带有“CppTest_Factory_”前缀的函数。函数返回类型定义了使用给定的工厂函数将创建哪种类型的对象。工厂函数可以接受参数,使其变得可参数化。例如,以下是一个包含许多字符串的 std::vector<string> 的工厂函数:
std::vector<std::string> CppTest_Factory_vector_of_strings(unsigned int size, const std::string&value) { std::vector<std::string> vec; for (int i = 0; i < size; i++) { vec.push_back(value); } return vec; }
详细信息请参阅使用工厂函数。
运行时错误检测
C++test 的运行时错误检测使团队能够在单元或应用程序级别自动识别严重的运行时缺陷,如内存泄漏、空指针、未初始化内存和缓冲区溢出。 它既适用于企业开发,也适用于嵌入式开发。
这种能力的可适应性使团队在使用非标准内存分配模型(例如,使用嵌入式系统)时也能利用运行时内存分析。由于用于该分析的插桩是轻量级插桩,因此可以在目标板、模拟器或主机上进行嵌入式测试。
详细信息请参阅运行时错误检测。
应用程序监控
应用程序监控旨在提供实际应用程序运行的测试结果。用于执行应用程序监控的插桩是轻量级的,适合运行在目标板上进行嵌入式测试。
C++test 可用于监控用 C++test 插桩准备的应用程序可执行文件的执行。它通常由开发人员和 QA 在常规应用程序测试阶段执行,以及其他补充性质量实践(同行评审、静态分析、单元测试等)
通过在测试期间启用应用程序监控,您可以访问 QA 阶段通常无法获得的详细信息,而无需测试人员进行任何额外的工作。唯一需要做的准备是应用程序需要通过 C++test 来构建。
应用程序监控分析可以提供:
- 覆盖率分析,提供与执行应用程序期间覆盖了应用程序代码哪些部分相关的信息。这有助于团队确定哪些源代码元素实现了应用程序级测试未覆盖的特定功能或用例。
- 运行时错误检测,用于检测诸如内存访问错误、内存泄漏、内存损坏等内存错误。
有关执行应用程序监控的详细信息,请参阅运行时错误检测。有关覆盖率分析的详细信息,请参阅覆盖率分析。
测试配置
测试配置是一系列设置的集合,定义了您想要使用 C++test 运行的测试场景。每次 C++test 在 GUI 中或从命令行界面运行测试时,它都会使用指定的测试配置(如果没有明确选择测试配置,则使用收藏的测试配置)。测试配置决定了所有测试参数。例如以下参数:
- 测试的类型(静态分析、测试用例生成、测试用例执行等)
- 静态分析期间检查的规则
- 测试用例生成的参数
- 每个测试的范围(覆盖哪些行、使用的截止日期等)
C++test 包含一组预配置的“内建”测试配置,代表着最常见的测试场景。您可以根据需要复制并修改内建配置来进一步自定义配置,或者从头开始创建新的用户定义配置。用户定义的测试配置放在用户自定义类别中。这些配置存储在本地机器上,可用于本地 C++test 安装程序执行的所有测试。
如果 C++test 连接到 DTP,则可以使用存储在 DTP 中的测试配置运行分析。
有关配置和共享测试配置的一般过程,请参阅配置测试配置和策略规则。有关特定的 C++test 测试配置选项的详细信息,请参阅配置测试配置。
命令行界面(cli)
通过 C++test 的命令行界面(cpptestcli
),您可以从命令行 shell 执行静态分析和单元测试,并通过自动构建实用程序(如批处理文件、脚本、make 和 Ant)运行 C++test。命令行模式可用于 C++test 的自动化版本。
cpptestcli
可以向 Parasoft DTP 发送结果,向团队经理发送综合报告,向开发人员发送重点报告。报告能够以 HTML、PDF 和自定义 XSL 格式生成。报告首选项(应将报告发送给谁、应如何标记这些报告、应使用什么邮件服务器和域等)、电子邮件设置、许可证设置等详细信息可以使用选项文件控制。
最佳团队配置:团队构建机器上有一个 C++test(自动化版),每个开发人员工作站上都有一个 C++test,架构师的机器上有一个 C++test,然后安装一个 Parasoft DTP。
开发人员使用他们本地安装的 C++test 来测试他们编写或修改的代码,进行必要的更正,然后将代码和测试用例签入源码控制。C++test 每天晚上以 cli 模式运行在团队机器上,验证签入的代码库;在这里,它会执行开发人员创建(通过自动测试生成和手动测试定义/定制)并添加到源码控制中的所有测试。测试完成后,团队开发人员就可以将测试结果导入 C++test GUI 进行检查和更改。此外,C++test 将结果发送到 Parasoft DTP。
有关使用命令行界面的详细信息,请参阅从命令行界面进行测试。
Parasoft DTP
Parasoft DTP 是一个决策支持系统,它为开发团队提供软件开发过程的持续可见性和度量能力,帮助确保软件项目按计划进行。DTP 收集和整合开发过程中生成的指标,将这些数据点转化为有意义的统计数据和仪表板,使开发经理和团队成员能够持续客观地评估代码库的质量和准备情况、编码过程的状态以及开发团队工作的有效性。有了 DTP,开发团队能够更容易识别、响应和管理代码或编码过程中威胁项目进度和质量的风险。Parasoft DTP 提供了多项指标,管理层可以通过这些指标更有效地评估和管理资源,设立和监控开发目标,传达、指导和判断开发政策的遵守情况,促成令人满意的项目成果。
将 C++test 被配置为向 DTP 发送信息后,开发人员、架构师和经理就可以通过不同角色使用 DTP 仪表板来访问关于质量、进度和生产率的报告。
有关如何连接到 DTP 的详细信息,请参阅连接 DTP。