使用 IBM Rational PurifyPlus

用测试自动化进行运行时分析

IBM® Rational® PurifyPlus™是一套测试工具集合,拥有三个工具-- PureCoverage、 Quantifyis 和 Purify,您可以用这套工具完成对代码覆盖率、性能和内存分析的运行时分析。它可以加强自动化测试工作,改善产品性能和质量。

Poonam Chitale (pchitale@us.ibm.com), 软件质量工程师, IBM

Poonam Chitale 在 IBM Rational Software 的 PurifyPlus 组担任软件质量工程师。她自 1998 年加入 Rational 以来一直从事有关运行时分析的测试项目。Poonam 是印度 Pune 大学的计算机硕士。



2007 年 10 月 09 日

引言

随着质量工程变得要求越来越高,能够使用更新的工具和方法对任何软件进行测试已经成为当务之急。

对很多团队来说,测试自动化已经成为他们的测试工作的核心。然而,即使在存在稳定的自动化测试时,您仍然需要对它进行维护:增加新的测试、修改现有的测试以及调整测试脚本以跟上产品的变更。但是对于寻找如何能够得到更好的回报来说,所有这些努力是值得的。

软件系统的规模和复杂性在持续增加,测试自动化也有相同的趋势。测试装备也要变得更大,能够进行更多的维护工作和更密切的监视工作,以便能够进行快速、可靠和更精确的测试。为了做到这些,您需要正确的工具。

IBM Rational PurifyPlus 是三种工具:IBM Rational PureCoverage®、IBM Rational Quantify®和 IBM Rational Purify®的集合。这些产品非常适合测试人员(和开发人员)在软件测试期间使用。

不只是测试自动化

只完成测试自动化工作是不能下产品可以发布的结论的,您仍然需要在测试装备的设计、评审和维护方面进行合适的投资,否则您的客户仍然会找到那些漏到产品中的难以发现的缺陷。

当给您(作为测试人员或者质量管理人员)安排一个测试任务时,您最好问自己以下的问题,以便更好地理解测试任务。

  • 我在这里做什么工作?
  • 有什么可用资源可以帮助我完成这个任务?
  • 如果我运行了所有针对应用程序计划的测试以后,则个任务是否就算完成了?
  • 自动化的测试是否包括了大多数的应用?
  • 有什么东西能够帮助我更彻底地测试,以便我能完成测试任务?

理解应用程序在测试时的行为,以及收集有关自动化测试运行时的有价值的信息,能够极大地改善测试的效率。这也有助于减少遗漏到您的用户手里的缺陷的数量。

在进行测试时,您应该集中在寻找最多的缺陷以便提高产品质量,而仅仅是完成测试任务。

这就是运行时分析:分析运行的程序并收集数据,用来帮助您理解软件的行为和软件不同部件之间的关系。

运行时分析

在软件开发期间可以把运行时分析作为一项高级调试和测试技术来考虑。

在运行应用程序期间,您可以收集和研究以下运行时数据:

  • 代码覆盖率
  • 性能瓶颈
  • 线程问题
  • 执行路径
  • 运行时跟踪
  • 内存错误和内存泄漏
  • 不正确的内存使用

下面是有关 PurifyPlus 的组件是如何设计以帮助您的一些细节:

  • PureCoverage 用来进行代码覆盖率分析:它测量在所有测试用例中多少代码运行了,多少代码没有运行
  • Quantify 用来进行性能分析:它帮助分析应用程序的性能瓶颈
  • Purify 用来进行内存分析:它帮助寻找应用程序的内存泄漏和错误的内存使用,这些有可能导致应用程序崩溃。

PurifyPlus for Microsoft® Windows® 可以用来分析 C++、Java™或者托管代码。它也可以集成在 Microsoft® Visual Studio® .NET IDE 中。

PurifyPlus for Linux® 和 UNIX® 可以用来分析 C/C++ 和 Java 应用程序,这些程序构建在 Red Hat、SUSE、Solaris™、HP-UX 和 AIX 平台。但是本文只介绍 Windows 平台的测试自动化和分析。

代码覆盖率分析

假设您已经为需求规格说明书中的每个功能点写了测试用例,并在一个稳定的自动化环境中运行了这些用例,结果是令人鼓舞的。然而,用户仍然报告出测试用例中没有发现的问题。这时代码覆盖率分析就有用了,它可以扩展您的视野。代码覆盖率分析可以针对您的测试用例的有效性给出有价值的反馈。

没有测试的代码

即使有大量的自动化测试,总会有测试不到的代码路径。这就产生了用户发现问题的危险,而您却很容易地发现有问题的部分已经在测试中"覆盖"到了。这在引入了一些没有合适文档化、从而没有建立测试用例的特性时是有可能的。另一个可能性是新的代码可能引入了一些行为变更。

进行代码覆盖率分析的主要步骤为:

  1. 自动化运行由 PureCoverage 处理过的应用程序
  2. 收集覆盖率数据
  3. 分析数据,找到哪些代码没有运行
  4. 增加测试用例,尽可能地覆盖没有运行的代码
  5. 运行增加了测试用例的自动化测试
  6. 确认增加的用例改善了您的覆盖率

这里有一个使用 PureCoverage 运行 Java 自动化测试的例子。ClassicsJava 是一个示例程序,功能是对数据库中的音乐 CD 进行排序。这个程序是 IBM Rational Functional Tester 中的一个示例程序。首先使用以下命令由 PureCoverage 对程序进行处理:

Coverage/java java.exe –jar ClassicsJavaA.jar

然后运行这个程序的自动化测试脚本。完成排序后,中止程序。在图1中,被覆盖的方法加上了Hit标签,没有覆盖的则加上Missed标签。

图1:PureCoverage 显示自动化测试程序的 hits 和 misses
Module View tab with coverage and calls

冗余度测试

覆盖率分析也可以帮您找到测试用例是否有冗余:测试在代码的同一路径下反复运行,导致了不必要的时间延迟。另外它也可以帮助您确认测试数据。例如,一个新引进的代码变更需要您运行自动化测试以进行回归确认。这时您就需要检查覆盖率分析的数据,以帮您确定哪些自动化测试的子集需要运行,这样就可以让您在更短的时间内验证新的代码。

为了深入到特定的方法内部,可以使用 PureCoverage 的 Annotated Source 特性。为了查看 Annotated Source 视图,双击方法。为了让这个特性工作,源代码必须可用。一种处理方法是使用开发人员的工作环境和软件,这样所有的源代码路径都可很容易地访问。图2显示出方法 Annotated Source 视图。正如同图1显示的那样,这个方法被遗漏了,因此代码行用红色字体显示。

图2:PureCoverage 显示方法getCustomerNames() 的注释源视图
missed method shows in red font

性能分析

性能分析是另外一种技术,它与 test harness 关联,给出有关应用程序的启发式的结果。在新 Build 的自动化测试明显变慢时,找到源代码内部发生了什么是至关重要的。导致变慢的原因是什么?这里有几个可能的原因:

  • 源代码中引入的变更:可能有不必要的模块导致了运行变慢,也可能是算法的改变影响了性能。
  • 测试代码的变更:您增加的用来改善代码覆盖率的测试用例可能导致变慢,也有可能这部分代码特别容易影响速度。
  • 测试数据的变更:大量的测试数据(或者不常见的数据)可能对代码产生压力,导致瓶颈。
  • 环境的改变或者连接问题:如果网络变慢,可能是您的硬件需要升级了。

您不应该依赖于简单的“注意到”测试 运行了很长时间后才报告性能问题。建立一种测量性能的方法是有意义的。有多种方法来发现性能问题:

  • 在自动化测试时记录时间信息
  • 在测试脚本中生成记录时间的日志
  • 写专门的测试用来测量性能
  • 使用与测试协同工作的性能监控工具

PurifyPlus 中的 Quantify 部件是一个性能监控的工具,您可以用它来收集性能数据。图3给出使用 Quantify 进行测试的 ClassicsJava 程序的一个例子。程序已经预先处理过,然后运行自动化测试(与 PureCoverage 的技术类似)。

图3:Quantify生成的Callgraph显示出最花时间的方法
details show method, class, and so on

Quantify 收集有关哪些方法是调用者还是子调用者,以及这些调用花费了多长时间的信息。您可以检查这些信息以确定是否有可以优化的地方。

在使用 Quantify 之前使用合适的过滤器是很重要的,否则将收集到太多的数据,很难进行分析。

使用 Quantify 进行性能分析的步骤如下:

  1. 决定何时收集数据。自动化测试需要在不崩溃的情况下,能够稳定运行足够合理的时间。
  2. 设置基准,以对比特定数量的测试的期望的时间和实际的时间。
  3. 使用处理过的程序运行自动测试。
  4. 分析收集到的数据,确定哪些测试或者方法看起来有问题。
  5. 识别和研究这些问题,看看是否可以修正,然后重复整个过程。

把性能分析的结果发给您的软件开发人员,让他们找找是否有办法阻止程序变慢。同时,您也要寻找是不是什么样的变更都会引起性能下降。如果是这样的话,基准就需要调整以便下一次任何更多的性能下降变得明显。

进行这种类型的分析有更多的价值,因为它对自动化测试和被测试的应用程序都有利。有时它还可以由别的用途,例如,自动化测试运行的很慢,因此不能对被测程序进行更多的测试。测试可能整理为每天晚上进行一部分,而不是一次运行全部测试。这时,使用性能分析工具将有助于合理分配测试,因为工具可以和软件结合用来收集性能数据。您需要确定的是哪个工具最适合您的应用,以及如何用这个工具在自动化测试运行时收集到的数据计划时间花费。

内存分析

运行时内存错误和泄漏时应用程序中最难检测的问题之一。它可能有随机触发,并且相当难预期。Purify 能够帮助检查出这些类型的错误。Purify 非常容易使用,它有大量的命令行接口帮助您获得正确的信息。

下面的列表是非常简单的错误内存使用的例子。他们看起来很简单,但是这种简单是具有欺骗性的。这是因为,在一个非常大的应用程序的小模块中,它们可能随机出现。如果这样的代码片段在应用程序运行期间一再地使用,问题就会累计,最终导致应用程序崩溃。

列表1:内存泄漏
// Allocate memory 1K 
    (void) new char[1000];
…..
//Forget to de-allocate later in the program
列表2:使用未初始化的内存
  char *string1 = "start";
  char *string2 = malloc(10);
  
  length = strlen(string2);
//string2 is not initialized like string1

程序崩溃

假如自动化测试运行的相当好,所有的测试都报告成功,性能也很好。然后,突然,出现了一个崩溃中止了测试过程。测试人员抱怨说,"运行测试时似乎有问题出现,应用程序有时候崩溃,但有时候却很好。"

很多质量工程师都遭遇过这种情况,并且这种应用程序的崩溃很难重现。一个原因是这种使用错误内存的症状距离实际出问题的代码比较远。有时一开始即使使用了错误的内存,应用程序似乎也能正常工作。

下面是一些最可能导致内存问题的情况:

  • 代码依赖和冲突 在不同模块在同一时间运行时发生
  • 错误的内存使用 在使用内存分配和释放的函数不匹配时发生
  • 数据结构不正确的初始化 超出了分配内存的边界

在一些组织中,期望开发人员在检查他们的新代码前完成内存分析,以确信他们没有引入无意的错误。在测试应用程序时存在稳定的回归测试时,引入类似 Purify 的运行时错误检查工具就是比较明智的事情。工具既可以检查不同的模块,确保它们能够正确地共同工作,又可以揭示出在单独开发期间不明显的代码的依赖关系。

使用 Purify

为了在运行测试自动化时使用 Purify 进行内存分析,需要以下步骤:

  1. 把Purify合并到测试自动化中,以便它能够在后台尽量不受干扰地运行。这意味着您要用 purify /savetextdata 前缀运行您的程序,这与前面描述的 PureCoverage 和 Quantify 的技术类似。
  2. 收集运行时的信息。可能是泄漏、空指针或者错误的内存使用。
  3. 分析收集的所有数据,总结为一篇简单的文档,指出哪个测试或者代码部分导致了问题。然后把这些信息传给开发人员。
  4. 在问题解决后,重新运行 Purify 进行测试,并报告结果。

对于 C 和 C++ 程序看来说,Purify 的报告是类似 MLK(Memory Leak,内存泄漏),MPK(Potential Memory Leak,潜在的内存泄漏),ABR(Array Bounds Read,数组边界读取)等等的警告、错误和信息。每个这种 Purify 的缩写都表示一种应用程序中出现的内存错误。

图4:一个测试 C++ 应用程序的自动化报告
Data Browser Error View

对于 Java 和其它托管代码的程序,Purify 收集哪些方法或者类负责分配最多的内存,如图 5 所示:

图5:在 Purify 下运行 classicsjava 自动化测试的 Function Detail 视图
Purify'd java.exe

这样可以找到应用程序执行期间全部内存使用的图形,对于找到哪些对象是不需要的非常有用。

使内存分析成为习惯

在测试自动化中增加内存分析工具将会增加组织的总体效率。测试自动化已经用开发组可能不知道的方法检查了他们的代码。另外在您使用内存分析工具收集相关数据时,可以减少开发人员花在调试和寻找问题所在的时间。

有时,依赖于您的组织的技能水平和时间限制,更可取的方法是收集运行时数据然后直接传给开发组进行分析和研究。寻找内存问题不需要一定有系统崩溃的情况发生。只要源代码发生变化,分析可以一直进行,以看看有什么发现。

了解何时使用哪个工具的最好的组合

我们作为质量工程师,没有必要为了进行运行使分析而等着问题出现。事实上,一个好的习惯是假设应用程序存在问题,然后进行运行时分析以找到问题所在。

您发现性能和内存瓶颈越早,就能够越早地修复它。有些问题需要重新编程并改变模块的全部代码逻辑。有些编程语言提供收集运行时更多信息的特性(如 assert 和异常处理)。更多的程序员在他们应用程序的调试版本中使用多种寻找内存问题的方法。他们甚至在他们的程序中写入测量性能的代码。

调试和运行时分析

然而,在调试和运行时分析之间仍然是有差异的。调试经常是由开发人员运行的,用来在运行他们自己的模块期间帮助他们找到小一些的问题。但是运行时分析则是一种应用于整个应用程序的方法,它可以由测试人员或者开发人员进行,或者二者都进行。

覆盖率分析在您使用自动化时更有效率。为了测量测试花了多少时间,自动化测试应该是可用的。当然,您完全可以使用手工测试来完成覆盖率分析。

在特定的时间进行那种类型的分析更有效果?对这个问题,一个简单的指导是看您发现的用户问题的类型,然后确定他们属于下面三个类别的哪一种或哪几种,再选择需要进行的分析组合。

  • 发现的问题没有被测试过:代码覆盖率问题
  • 与大量数据或者特定的数据有关的速度变慢的问题:性能问题
  • 在用户使用时程序死机或者突然崩溃:内存问题

在开发人员和测试人员之间建立桥梁

共同使用测试自动化和运行时分析是一个明智的策略,这样可以有助于发布高质量的软件的最终目标。它可以最小化您的用户发现的缺陷的数量,同时增加您的开发人员和测试人员的自信心。

在运行分析之前,突然出现的未预料的系统崩溃将会给您的团队极大的挫折。然后他们会受益于对软件行为和相关的复杂性的更深刻的理解。有可行修正全部问题,也可能不能完全修正,或者完全改善测试的覆盖率,但是对问题的理解有助于您对未来的规划。

使用 test harness 作为可用工具的一种,然后与分析工具组合起来,可以帮助您找到那些隐藏的问题。运行时分析可以在软件开发生命周期的任何一点完成,即使没有自动化测试的存在也可以进行。它甚至可以在全部的代码还不可用的时候进行。开发人员可以使用运行时分析工具和技术识别和解决他们调试和单元测试中发现的问题。

这个方法有助于在开发人员和测试人员之间建立桥梁。他们可以共同工作,发现软件中的问题,而不是由用户发现问题。这也可以帮助改善开发人员和测试人员之间的通讯。测试人员可以用“白盒”的方式深入到源代码中,更好地理解他们测试的软件。另外,在测试人员报告他们运行时发现的问题时(不管是性能问题、内存问题还是代码覆盖),他们都可以给开发人员以实际的反馈,告诉他们应该修改什么地方以提高质量。

致谢

作者在这里感谢 David Lofgren 对本文的审阅工作,并感谢 Don Nguyen 帮助准备了 Java 示例程序。

参考资料

学习

获得产品和技术

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Rational
ArticleID=265740
ArticleTitle=使用 IBM Rational PurifyPlus
publish-date=10092007