什么是单元测试
单元测试的定义是测试应用中最小的单元,单元测试被公认为软件开发过程中的一个关键步骤。单元测试能够简化错误检测,在减少开发时间和成本的同时提高软件质量。
为什么需要单元测试?
• 单元测试能帮助客户更准更全面地找到错误,显著提高软件质量
上图显示了一个包含许多对象的应用程序的测试模型,大椭圆表示应用程序,小椭圆表示对象,箭头表示用户输入,红星表示潜在的错误。
在集成测试中为了发现错误,我们希望通过不断修改输入,引发对象间的相互作用使得某对象引发潜在的错误,但这无疑是有难度的。由于其难度,开发人员只能依赖应用软件的运行失败来发现错误,这样不仅很难找到错误发生的准确位置,而且实际上还有大量的类没有得到测试。
单元级测试提供了一种更有效的发现错误的方法,它将应用程序中的最小单元分离开,使得测试更接近错误,只要简单地对每个最小单元进行独立测试,就很容易地使全面准确地找到所有的程序错误成为可能。
• 单元测试能够在改善软件质量的同时大量削减开发时间和成本
由于在较高的层次上修改一个类可能会改变多个程序部件的设计和功能性,因此越迟发现问题,通常就要修改越多的代码。当修改的代码量增加时,其他两个因素也会随之增加:
• 修改每一个错误所需的时间和费用
• 在代码中引入新的错误的机会
一次又一次的研究证明,随着问题被检测出来的时间的推迟,发现软件错误所需的时间和成本会惊人地增加。而单元测试由于能够更容易地找到错误,就会减少发现它们的时间和资源。
其次,由于你每完一个类,就能发现和改正其中的错误,你就不需要在以后花费大量时间重新了解和摸索。
最后,最重要的理由是由于类的相互作用和关联性,在单元级修改一个类只会影响到原始的类,避免了各个单元间的相互作用引发新的错误。因此单元测试能保证大大削减开发的时间和成本。
什么是单元测试的难点 ?
基于上述信息,单元测试看上去就象一剂万能药 如果是这样的话,为什么每一个 C/C++ 开发人员不马上对每一个类进行单元测试?就目前可以使用的技术来说,对 C/C++ 的单元测试是一件困难、烦琐和耗时的事情,没有很好的工具来自动化这一过程,使得许多 C/C++ 开发人员望而生畏。
执行单元测试的第一步是是目标类变得可测。这需要两个工作:
• 设计一个运行目标类的测试驱动程序
• 设计桩函数,它们为被测类所引用的任何外部资源返回值
建立一个测试驱动,需要建立一个新的类,除了测试原始类以外它不能用于任何其它目的。测试驱动应该具有下列特性:
• 一个指定设置和清除的标准方式
• 一个选择个别测试和所有有效测试的方法
• 一个分析输出的预期(或非预期)结果的机制
• 一个标准的错误报告形式
为了充分而正确地测试类,你需要设计一个能够完全检查被测类的测试驱动;若干次修改和重写这样一个测试驱动是免不了的。一旦建立了测试驱动,你必须仔细检查它不能包含任何错误。测试驱动中的一个错误会破坏这个测试,但是你无法单独测试一个类,你也不能测试测试驱动本身。
如果你的类引用任何还没有准备好或不可访问的外部资源(如外部文件、数据库和 CORBA 对象等),你必须建立相应的桩函数,它们的返回值类似于这些实际的外部资源应该返回的。当建立这些桩函数时,你需要选择桩函数的返回值,它们将影响程序的执行路径:
• 为了测试类的功能性必须执行任何的路径
• 足够的路径能够提供彻底的测试覆盖性
下一步是设计和建立合适的测试用例。为了彻底地测试类的结构和功能性,你应该设计两种类型的
测试用例:黑盒和白盒。
黑盒测试
黑盒测试用例基于说明和规格文档 。 特别地,至少应该为规格文档的每个入口建立一个测试用例 , 更好的是这些测试用例能够测试每个入口的各种边界条件 , 还需要为发现的每一个错误增加另外的测试用例以及任何你认为必要的其它测 试。
白盒测试
为了建立有效的白盒测试用例,你必须研究类的内部结构,然后编写测试用例尽可能完全地覆盖类的所有方法,以及覆盖所有可能引起类崩溃的输入。要达到较高的测试覆盖性,需要有效的白盒测试用例,并且要求它们能够执行相当多的路径。例如,一个典型的万行的程序,大约有上亿条可能的路径,而手工建立能够执行所有这些路径的输入几乎是不可能的。
回归测试
任何时候一个类被修改后,你应该执行回归测试,保证没有引入新的错误和 / 或原来的错误已经被更正了。回归测试包括白盒和黑盒测试用例,并且分析结果以确定类的质量是否得到了改善
覆盖率测试
在建立测试用例以后,你将要执行整个测试用例并分析结果,确定在那里出现了错误崩溃和薄弱环节 你还需测量这些测试的覆盖性,以确定类被测试的程度以及需要追加的测试用例。
• 什么是 C++test ? ?
C++test 是一个 C/C++ 自动单元测试工具,自动测试任何 C/C++ 类、函数或部件,自动生成测试用例、测试驱动程序或桩调用,无需手工编写。 C++test 能够自动测试代码构造(白盒测试)、测试代码的功能性(黑盒测试)和维护代码的完整性(回归测试) ,并提供自动覆盖率测试 。
同时 C++test 还是一个 C/C++ 编程规范自动检查工具,它内置了 8 00 多条业界规则,同时可以图形化地定制自己的规则。
C++test 的特性:
• 即时测试类 / 函数
• 支持极端编程模式下的代码测试
• 自动建立类 / 函数的测试驱动程序和桩调用
• 自动建立任何必要的桩函数,并允许你定制这些桩函数的返回值或加入自己的桩函数
• 自动执行白盒测试的所有步骤
• 自动生成黑盒测试用例的基础集合、自动运行黑盒测试用例并生成黑盒测试的输出结果
• 自动建立和执行类 / 函数的测试用例
• 自动执行回归测试
• 自动跟踪测试覆盖性
• 与 IDE 的高度集成
C++test 的好处:
• 在开发进程的任何阶段帮助您立即验证类功能性和构造
• 自动化的测试将您从编写测试驱动程序、桩和测试用例的繁重工作中解放出来
• 自动化极端编程和其它编程模式的单元测试过程
• 使得您能够实现和执行 100% 的代码覆盖性
• 对紧急和短线开发项目提供特别支持
• 大幅降低调试和维护时间以及人力成本
• 最短时间内显著改善应用的可靠性
• 防止简单错误的扩大
• 根据客户的实际开发环境,提供灵活周全的合作开发方式
• 使项目管理者获得量化的数据监督项目的开发进程
• C++test 能做什么?
• 自动建立测试驱动和桩函数
C++test 自动建立一个测试驱动程序,其设计目标是极大化类的测试覆盖性和错误检测 。 为类建立测试驱动,你只要简单地打开这个类,然后按 Build Test 键 , C++test 将自动建立测试驱动程序 。
另外,如果被测的方法需要调用当时还不存在或无法访问的函数, C++test 能够自动生成桩函数;这样能够测试与外部资源操作的交互作用和不包含任何隐藏的弱点 。 C++test 不是实际调用这些函数,而是调用桩函数并返回桩函数提供的值 。如果你需要控制使用的返回值, 你可以建立一个桩调用表, 申明 输入 / 输出的关系。
你还能加入用户定义的桩函数 例如,如果你要使用原始的函数,且该函数定义在不同的文件中,或者你想要仿真原始函数的行为,而用一个简单的函数替代它。
自动生成 C/C++ 类的测试驱动程序和桩函数的能力是 C++test 所独有的;只有 C++test 能够自动测试 C/C++ 类(一旦它能够被编译时),而不需要用户的任何干预。使得你能够尽快地自动检测代码错误,以最容易、最省钱和最快速的方法找到和修正它们。如果没有这样的自动化工具,大量的时间和资源消耗将失去单元测试的潜在好处和现实意义。
• 自动静态测试( 自动编程规范检查 )
• Pattern Matching (自动代码走查)
• 内置 8 00 多条业界有名的 C/C++ 规则 (大量规则来自于多家世界著名电信公司的编程规范,以及世界权威的编程规范资料), 可实现自动 的图形化 代码编程规范检查 ;
• 使用 RuleWizard 图形化 建立 自定义代码规则的功能 。客户可以很方便 建立 并保存 一整套自己的代码 编程 规范 (团队经验),从而保证团队经验不会因为人员变动而流失。与此同时避免了编程人员为了保存团队的代码编程规范而浪费大量时间人工编写 script 。
• Bug Detective ( Flow Analysis )
• Hot Spot 技术(“热点”技术)。 C++test 通过自带的“热点”包,用回溯的方式自动模拟运行程序中的执行路径,从而精确高速地找到程序存在问题的位置;例如,我们不允许程序中存在“ /0 ”的运算部分,由此凡是程序中“ /var ”的部分都有可能因为 var 是 0 而造成程序逻辑错误(其中“ /var ”的型态就称为程序中的“热点”),此时, C++test ?会自动搜索程序中所有“ /var ”的运算型态,并回溯运行程序中的执行路径,找到所有致使 var 变成 0 的路径,从而精确地找到程序中的错误。
• 自动 动态 测试 (白盒 / 黑盒 / 回归测试)
C++test 能自动建立测试环境,自动分析代码,自动生成测试用例并测试驱动程序和桩函数,自动执行白盒、黑盒和回归测试。
• 白盒测试(坚固性测试)
C++test 提供了一种有效并且高效的方法执行白盒测试。完全自动执行所有的白盒测试过程,自动生成和执行精心设计的测试用例。自动标记任何运行失败,并以一种简单的图示化结构显示。然后自动保存这些测试用例,能够方便地用于以后的回归测试。
• 由于 C++test 能够自动生成桩函数,或允许你加入自己的桩函数,因此它能够测试引用外部对象的类。换句话说, C++test 能够运行任何一个或一组类,并自动生成和执行一组测试用例,它们被设计成能够发现尽可能多的错误。
• C++test 允许你定制白盒测试用例的生成,和在什么层次上(项目、文件、类或方法)执行测试。
• C++test 通过自动生成大量测试案例,向程序输送各种合法以及非法数据,考察程序是否会由于非法数据的输入而产生异常,导致程序不可控。从而检测程序的坚固性。
• C++test 能够使用客户自己的数据源( Excel , SQL Server , Oracle 等)作为测试用例的输入数据并自动生成测试用例进行测试。
• C++test 能够全自动地生成被测单元的桩函数,从而使单元测试能在一个完全不依赖被测单元外部因素的基础上自动进行。
优点:
• 单元测试不会由于被测单元在调用团队内其他未完成单元的情况下延迟或失败
• 单元测试不会由于被测单元在无法调用其他团队,甚至其他公司的单元的情况下延迟或失败
• 桩函数可以根据开发人员的实际需要,通过修改桩函数代码,改变桩函数的返回值,以满足代码测试的各种特殊需要。
• 自动生成测试报告,并以 email 或者 html 的格式提供给客户。
• 黑盒测试(功能性测试)
C++test 能根据程序功能定义好的每个入口,自动生成大量的具功能性的测试用例,对程序进行功能测试,从而检测程序的功能。通过自动化黑盒测试的大部分操作,减轻了这类测试的负担。
• 帮助你设置每个测试用例的结果。
你可以简单地输入测试用例输入,然后让 C++test 运行测试用例并自动确定实际的输出结果。如果结果正确,不需要其它动作。如果结果不正确,你可以输入预期的输出结果。这样比手工输入每个测试用例的结果更快更容易
• 自动生成测试用例的核心集。
C++test 自动设计了一组广谱的白盒测试用例。当使用这些测试用例在黑盒测试时,你只需简单地观察实际的输出结果,然后对任何不正确的结果输入预期的值。当你需要输入或修改测试用例时,你可以在 C++test 自动生成的测试用例框架种简单地键入相应的值。这将显著地加快建立测试用例的过程。
• 在自动化建立黑盒测试用例的大多数步骤之外, C++test 完全自动化余下的黑盒测试步骤。
按一个键,你能够选择对项目、文件、类或方法运行一个或一组测试。 C++test 然后自动执行所有的测试用例,报告所有的输入 / 输出关系,并标记任何实际输出与预期不一致或导致程序崩溃的测试目标。
• C++test 能够使用客户自己的数据源( Excel , SQL Server , Oracle 等)作为测试用例的输入数据并自动生成测试用例进行测试。
• C++test 能在不修改客户源码的前提下,自动高速生成大量的具功能性的测试案例,并在最短时间内显著提升客户的测试覆盖率。
• 回归测试(代码的完整性测试)
C++test 完全自动化与回归测试有关的所有步骤。
C++test 首次测试某个类时,自动保存其测试和测试参数。当需要执行回归测试时,你可以打开合适的项目和文件,运行所有原来的白盒和黑盒测试用例, C++test 会自动运行完全相同的测试用例和测试参数,并告之发现的任何问题。这意味着你能够立即知道修改是否引入了任何错误。
• 集成的单步调试
如果你选择在方法测试时捆绑调试器, C++test 将自动自动激活 Microsoft Visual C++ 调试器,这样使得你在用 C++test 测试任何方法时仍然能够方便地进行单步调式。
• 防止错误
C++test ?能够自动执行两种类型的编程标准。其内建的特性允许你自动执行动态的编程标准,如“总是对每个类执行单元测试”和“总是单步调试类”等。另外,假如你使用 CodeWizard-Parasoft 的自动化可定制编程标准强化工具, C++test 可以自动运行 CodeWizard 。
• 运行时错误检测
C++test 还能帮助你执行类一级的运行时错误自动检测。如果你安装了 Insure++ , C++test 可以自动
运行类和方法。通过 Insure++ ,它将检查下列错误:
• 内存引用错误 / 内存未初始化
• 内存泄漏
• 内存分配错误
• 变量定义冲突
• I/O 错误
• 指针错误
• 库调用错误
• 逻辑错误
• 算法错误
这意味着你能够在类开发的第一时间检测运行时错误,而且无需自己手工编写任何运行数据。
C++test 自动生成大量而精心设计的测试用例,能够帮助你更彻底、更方便和更快速地检测运行时
错误。
• 桩函数设置
C++test 自动生成被测函数的桩函数。它可以按 “ 自动生成桩函数 ” 、 “ 使用原函数作为桩函数 ” 和 “ 自定义桩函数 ” 等三种方式生成桩函数。
• 兼容 CppUnit 测试用例
C++test 可以生成 CppUnit 测试用例和图形化测试用例两种测试用例。可以把 CppUnit 测试用例导入到 C++test 中使用,也可以把 C++test 自动生成的 CppUnit 格式测试用例输出到 CppUnit 环境下使用。
• 覆盖率分析
为了帮助你测量当前使用的测试用例集合的有效性,并且给你提供达到尽可能高的覆盖性的信息, C++test 自动监视测试覆盖性。
C++test 实时跟踪测试覆盖性,然后建立一个综合测试覆盖性报告。覆盖性窗口图示化地说明了当前正在被执行的代码行,已执行过的行和每行的执行次数。因此,它不仅指出了一个代码行是否被测试过,而且说明了被测试的有多彻底。这些信息对于确定那些代码需要追加测试是非常有帮助的。
C++test 能自动 显示被测代码的各种覆盖率状况,分为:
• Line Coverage :语句覆盖
• Basic Block Coverage :没有包含分支,控制流转的一段代码覆盖
• Path Coverage :一条从函数入口到出口的路径覆盖
• Decision (Branch) Coverage :分支覆盖
• Modified Condition/Decision Coverage (MC/DC) : MC/DC 覆盖 (符合 NASA 的 DO178B 标准)
• Condition Coverage :条件覆盖
• 导入导出测试用例
C++test 可以导入和导出一个函数、一个文件和整个工程的测试用例。我们甚至可以保存整个 C++test 测试工程作为整个产品的一部分(就像项目文档一样是产品的一部分)。
• RuleWizard 定制规则
RuleWizard 是个图形化的编程规范定制工具。可以 很方便地 修改现有规则, 甚至 可以 在图形化的环境下 完全建立一个新的自己的规则。
• 高级特性
C++test 的高级特性可以帮助我们快速地定制符合业务要求的测试用例,特别是满足特定要求的黑盒测试用例。它提供一些非常有效的功能来大幅度提高单元测试效率。简介如下:
• 直接导入 VC++ 等 IDE 工程或者通过 makefile 文件导入一个 无集成开发环境( IDE )的 工程。
• DataSource :用 excel 文件, CSV 文件或数据库的表作为测试用例的输入,自动生成一系列的有规律的测试用例。
• TestObjects :使用一些特殊或定义好的值构造一个类对象,在其他地方使用此类的时候,就可以重复使用此对象。
• 版本和 License
• C++test Professional Edition :
自动单元测试,自动编程规范检查和自动生成测试报告。
• C++test Architect Edition :
自动单元测试,自动编程规范检查和自动生成测试报告; RuleWizard 图形化定制规则。
• C++test Server Edition :
自动单元测试,自动编程规范检查和自动生成测试报告; RuleWizard 图形化定制规则; Command line 支持命令行功能。
• 可选 License
Security :静态分析源代码,分析代码路径,模拟执行各路径,找到各种潜在的错误。
• 支持平台
1. W indows
Windows NT, Windows 2000, or Windows XP
Compiler: Microsoft? Visual C++ 6.0, .NET, .NET 2003, or 2005; GCC 2.95.x, 3.2.x, 3.3.x, or 3.4.x; Green Hills MULTI for Windows x86 Native v4.0.1
2 . UNIX
Solaris 7, 8, 9 and an UltraSPARC processor
Compiler: GCC 2.95x, 3.2.x, 3.3.x, 3.4.x, or 4.0.x; Sun? C++ 5.3 (Sun Forte C++ 6 Update 2), Sun C++ 5.5 (Sun ONE Studio 8), or Sun? C++ 5.6 (Sun ONE Studio 9); Green Hills MULTI for SPARC Solaris Native v4.0.1
3 . Linux
Linux Red Hat kernel 2.4 (with System V IPC) or higher with glibc 2.2 or higher and an x86-compatible processor
Compiler: GCC 2.95x, 3.2.x, 3.3.x, 3.4.x , or 4.0.x
• 总结
通过执行单元测试,你能够有效地防止许多错误的出现,尽早检测出已存在的错误,并且比其它测试手段和技术更有效 影响 C/C++ 开发人员执行单元测试的主要障碍是需要消耗大量的时间的资源,目前的一些单元测试工具仍然存在着这样的问题。 C++test ?的推出克服了这一障碍,做到了开发人员总是希望却不敢相信的事情:自动化 C/C++ 单元测试。