日历
| |||||||||
| 日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
| 1 | 2 | 3 | 4 | ||||||
| 5 | 6 | 7 | 8 | 9 | 10 | 11 | |||
| 12 | 13 | 14 | 15 | 16 | 17 | 18 | |||
| 19 | 20 | 21 | 22 | 23 | 24 | 25 | |||
| 26 | 27 | 28 | 29 | 30 | 31 | ||||
搜索标题
最新来客
我的好友
我的收藏
统计信息
- 访问量: 2323
- 日志数: 10
- 书签数: 1
- 建立时间: 2007-06-08
- 更新时间: 2008-07-22
我的最新日志
-
使用 IBM Rational PurifyPlus
2008-4-07
IBM® Rational® PurifyPlus™是一套测试工具集合,拥有三个工具-- PureCoverage、 Quantifyis 和 Purify,您可以用这套工具完成对代码覆盖率、性能和内存分析的运行时分析。它可以加强自动化测试工作,改善产品性能和质量。
随着质量工程变得要求越来越高,能够使用更新的工具和方法对任何软件进行测试已经成为当务之急。
对很多团队来说,测试自动化已经成为他们的测试工作的核心。然而,即使在存在稳定的自动化测试时,您仍然需要对它进行维护:增加新的测试、修改现有的测试以及调整测试脚本以跟上产品的变更。但是对于寻找如何能够得到更好的回报来说,所有这些努力是值得的。
软件系统的规模和复杂性在持续增加,测试自动化也有相同的趋势。测试装备也要变得更大,能够进行更多的维护工作和更密切的监视工作,以便能够进行快速、可靠和更精确的测试。为了做到这些,您需要正确的工具。
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 平台的测试自动化和分析。
假设您已经为需求规格说明书中的每个功能点写了测试用例,并在一个稳定的自动化环境中运行了这些用例,结果是令人鼓舞的。然而,用户仍然报告出测试用例中没有发现的问题。这时代码覆盖率分析就有用了,它可以扩展您的视野。代码覆盖率分析可以针对您的测试用例的有效性给出有价值的反馈。
即使有大量的自动化测试,总会有测试不到的代码路径。这就产生了用户发现问题的危险,而您却很容易地发现有问题的部分已经在测试中"覆盖"到了。这在引入了一些没有合适文档化、从而没有建立测试用例的特性时是有可能的。另一个可能性是新的代码可能引入了一些行为变更。
进行代码覆盖率分析的主要步骤为:
- 自动化运行由 PureCoverage 处理过的应用程序
- 收集覆盖率数据
- 分析数据,找到哪些代码没有运行
- 增加测试用例,尽可能地覆盖没有运行的代码
- 运行增加了测试用例的自动化测试
- 确认增加的用例改善了您的覆盖率
这里有一个使用 PureCoverage 运行 Java 自动化测试的例子。ClassicsJava 是一个示例程序,功能是对数据库中的音乐 CD 进行排序。这个程序是 IBM Rational Functional Tester 中的一个示例程序。首先使用以下命令由 PureCoverage 对程序进行处理:
Coverage/java java.exe –jar ClassicsJavaA.jar然后运行这个程序的自动化测试脚本。完成排序后,中止程序。在图1中,被覆盖的方法加上了Hit标签,没有覆盖的则加上Missed标签。
图1:PureCoverage 显示自动化测试程序的 hits 和 misses
覆盖率分析也可以帮您找到测试用例是否有冗余:测试在代码的同一路径下反复运行,导致了不必要的时间延迟。另外它也可以帮助您确认测试数据。例如,一个新引进的代码变更需要您运行自动化测试以进行回归确认。这时您就需要检查覆盖率分析的数据,以帮您确定哪些自动化测试的子集需要运行,这样就可以让您在更短的时间内验证新的代码。
为了深入到特定的方法内部,可以使用 PureCoverage 的 Annotated Source 特性。为了查看 Annotated Source 视图,双击方法。为了让这个特性工作,源代码必须可用。一种处理方法是使用开发人员的工作环境和软件,这样所有的源代码路径都可很容易地访问。图2显示出方法 Annotated Source 视图。正如同图1显示的那样,这个方法被遗漏了,因此代码行用红色字体显示。
图2:PureCoverage 显示方法getCustomerNames()的注释源视图
性能分析是另外一种技术,它与 test harness 关联,给出有关应用程序的启发式的结果。在新 Build 的自动化测试明显变慢时,找到源代码内部发生了什么是至关重要的。导致变慢的原因是什么?这里有几个可能的原因:
- 源代码中引入的变更:可能有不必要的模块导致了运行变慢,也可能是算法的改变影响了性能。
- 测试代码的变更:您增加的用来改善代码覆盖率的测试用例可能导致变慢,也有可能这部分代码特别容易影响速度。
- 测试数据的变更:大量的测试数据(或者不常见的数据)可能对代码产生压力,导致瓶颈。
- 环境的改变或者连接问题:如果网络变慢,可能是您的硬件需要升级了。
您不应该依赖于简单的“注意到”测试 运行了很长时间后才报告性能问题。建立一种测量性能的方法是有意义的。有多种方法来发现性能问题:
- 在自动化测试时记录时间信息
- 在测试脚本中生成记录时间的日志
- 写专门的测试用来测量性能
- 使用与测试协同工作的性能监控工具
PurifyPlus 中的 Quantify 部件是一个性能监控的工具,您可以用它来收集性能数据。图3给出使用 Quantify 进行测试的 ClassicsJava 程序的一个例子。程序已经预先处理过,然后运行自动化测试(与 PureCoverage 的技术类似)。
图3:Quantify生成的Callgraph显示出最花时间的方法
Quantify 收集有关哪些方法是调用者还是子调用者,以及这些调用花费了多长时间的信息。您可以检查这些信息以确定是否有可以优化的地方。
在使用 Quantify 之前使用合适的过滤器是很重要的,否则将收集到太多的数据,很难进行分析。
使用 Quantify 进行性能分析的步骤如下:
- 决定何时收集数据。自动化测试需要在不崩溃的情况下,能够稳定运行足够合理的时间。
- 设置基准,以对比特定数量的测试的期望的时间和实际的时间。
- 使用处理过的程序运行自动测试。
- 分析收集到的数据,确定哪些测试或者方法看起来有问题。
- 识别和研究这些问题,看看是否可以修正,然后重复整个过程。
把性能分析的结果发给您的软件开发人员,让他们找找是否有办法阻止程序变慢。同时,您也要寻找是不是什么样的变更都会引起性能下降。如果是这样的话,基准就需要调整以便下一次任何更多的性能下降变得明显。
进行这种类型的分析有更多的价值,因为它对自动化测试和被测试的应用程序都有利。有时它还可以由别的用途,例如,自动化测试运行的很慢,因此不能对被测程序进行更多的测试。测试可能整理为每天晚上进行一部分,而不是一次运行全部测试。这时,使用性能分析工具将有助于合理分配测试,因为工具可以和软件结合用来收集性能数据。您需要确定的是哪个工具最适合您的应用,以及如何用这个工具在自动化测试运行时收集到的数据计划时间花费。
运行时内存错误和泄漏时应用程序中最难检测的问题之一。它可能有随机触发,并且相当难预期。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合并到测试自动化中,以便它能够在后台尽量不受干扰地运行。这意味着您要用 purify /savetextdata 前缀运行您的程序,这与前面描述的 PureCoverage 和 Quantify 的技术类似。
- 收集运行时的信息。可能是泄漏、空指针或者错误的内存使用。
- 分析收集的所有数据,总结为一篇简单的文档,指出哪个测试或者代码部分导致了问题。然后把这些信息传给开发人员。
- 在问题解决后,重新运行 Purify 进行测试,并报告结果。
对于 C 和 C++ 程序看来说,Purify 的报告是类似 MLK(Memory Leak,内存泄漏),MPK(Potential Memory Leak,潜在的内存泄漏),ABR(Array Bounds Read,数组边界读取)等等的警告、错误和信息。每个这种 Purify 的缩写都表示一种应用程序中出现的内存错误。
图4:一个测试 C++ 应用程序的自动化报告
对于 Java 和其它托管代码的程序,Purify 收集哪些方法或者类负责分配最多的内存,如图 5 所示:
图5:在 Purify 下运行 classicsjava 自动化测试的 Function Detail 视图
这样可以找到应用程序执行期间全部内存使用的图形,对于找到哪些对象是不需要的非常有用。
在测试自动化中增加内存分析工具将会增加组织的总体效率。测试自动化已经用开发组可能不知道的方法检查了他们的代码。另外在您使用内存分析工具收集相关数据时,可以减少开发人员花在调试和寻找问题所在的时间。
有时,依赖于您的组织的技能水平和时间限制,更可取的方法是收集运行时数据然后直接传给开发组进行分析和研究。寻找内存问题不需要一定有系统崩溃的情况发生。只要源代码发生变化,分析可以一直进行,以看看有什么发现。
我们作为质量工程师,没有必要为了进行运行使分析而等着问题出现。事实上,一个好的习惯是假设应用程序存在问题,然后进行运行时分析以找到问题所在。
您发现性能和内存瓶颈越早,就能够越早地修复它。有些问题需要重新编程并改变模块的全部代码逻辑。有些编程语言提供收集运行时更多信息的特性(如 assert 和异常处理)。更多的程序员在他们应用程序的调试版本中使用多种寻找内存问题的方法。他们甚至在他们的程序中写入测量性能的代码。
然而,在调试和运行时分析之间仍然是有差异的。调试经常是由开发人员运行的,用来在运行他们自己的模块期间帮助他们找到小一些的问题。但是运行时分析则是一种应用于整个应用程序的方法,它可以由测试人员或者开发人员进行,或者二者都进行。
覆盖率分析在您使用自动化时更有效率。为了测量测试花了多少时间,自动化测试应该是可用的。当然,您完全可以使用手工测试来完成覆盖率分析。
在特定的时间进行那种类型的分析更有效果?对这个问题,一个简单的指导是看您发现的用户问题的类型,然后确定他们属于下面三个类别的哪一种或哪几种,再选择需要进行的分析组合。
- 发现的问题没有被测试过:代码覆盖率问题
- 与大量数据或者特定的数据有关的速度变慢的问题:性能问题
- 在用户使用时程序死机或者突然崩溃:内存问题
共同使用测试自动化和运行时分析是一个明智的策略,这样可以有助于发布高质量的软件的最终目标。它可以最小化您的用户发现的缺陷的数量,同时增加您的开发人员和测试人员的自信心。
在运行分析之前,突然出现的未预料的系统崩溃将会给您的团队极大的挫折。然后他们会受益于对软件行为和相关的复杂性的更深刻的理解。有可行修正全部问题,也可能不能完全修正,或者完全改善测试的覆盖率,但是对问题的理解有助于您对未来的规划。
使用 test harness 作为可用工具的一种,然后与分析工具组合起来,可以帮助您找到那些隐藏的问题。运行时分析可以在软件开发生命周期的任何一点完成,即使没有自动化测试的存在也可以进行。它甚至可以在全部的代码还不可用的时候进行。开发人员可以使用运行时分析工具和技术识别和解决他们调试和单元测试中发现的问题。
这个方法有助于在开发人员和测试人员之间建立桥梁。他们可以共同工作,发现软件中的问题,而不是由用户发现问题。这也可以帮助改善开发人员和测试人员之间的通讯。测试人员可以用“白盒”的方式深入到源代码中,更好地理解他们测试的软件。另外,在测试人员报告他们运行时发现的问题时(不管是性能问题、内存问题还是代码覆盖),他们都可以给开发人员以实际的反馈,告诉他们应该修改什么地方以提高质量。
作者在这里感谢 David Lofgren 对本文的审阅工作,并感谢 Don Nguyen 帮助准备了 Java 示例程序。
学习
- 您可以参阅本文在 developerWorks 全球网站上的 英文原文。
- 密切关注 developerWorks 技术活动和网络广播。
- IBM Rational PurifyPlus 产品资源页面:查找有关 Rational PurifyPlus 的技术文档、教程、文章、培训、下载和产品信息。
- 浏览 技术书店,查找在这些以及其它主题方面的书籍。
获得产品和技术
- 下载一个 Rational PurifyPlus V7.0 的免费试用版本。
- 下载 IBM 产品评估版本,尝试 DB2®、Lotus®、Rational®、Tivoli® 以及 WebSphere® 的应用开发工具和中间件产品。
讨论
- 使用 PurifyPlus 产品族进行运行时分析的工具论坛:询问有关 Rational PurifyPlus 的问题。
- 进入 developerWorks 博客,加入到 developerWorks 社区。


Poonam Chitale 在 IBM Rational Software 的 PurifyPlus 组担任软件质量工程师。她自 1998 年加入 Rational 以来一直从事有关运行时分析的测试项目。Poonam 是印度 Pune 大学的计算机硕士。
-
面向开发人员和测试人员的IBM Rational PurifyPlus
2008-4-07
开发人员和测试人员能够在组织中扮演不同的角色,但都是为了最大化整个项目质量的共同目标。不管它意味着要增加客户想要的特征和性能,还是要确保这些特性能够很好的运转,您的项目小组都要维持一个高水平的质量来取得成功的机会。
IBM® Rational® PurifyPlus™ 能够帮助开发人员和测试人员达到他们项目质量的共同目标。有些人把 PurifyPlus 看作一个测试工具,有些人则将它看作是一个开发工具。开发人员和测试人员都可以从 PurifyPlus 获得利益,因为他们都是在软件项目中为高水平的质量而奋斗。
在这篇文章中,我展现了一个 PurifyPlus 的概述、它如何操作,以及为什么它对开发人员和测试人员有如此大的价值,通过许多重要的产品活动不仅仅提高了产品质量,还增加了个人和小组的效率和有效性。
低质量的成本
为了您项目的成功,尽早找到并修复故障是非常必要的。如果能够尽早找到并修复缺陷,这些缺陷的成本将少得多,要么通过开发人员要么通过早期得测试得方法来操作。故障如果通过了测试并到达了客户,成本将比找到并修复要高得多,而且对您得声誉和最终的业务也有相当大的影响。
在开发和测试阶段使用 PurifyPlus,您可以尽早将质量引入项目,并且可以避免不完全测试的高成本,处理性能问题,以及/或者稍后找到并修复内存使用错误。
PurifyPlus 组件
Rational PurifyPlus 产品有三个组件:内存错误验证的 Purify,性能数据采集的 Quantify,以及代码覆盖分析的 PureCoverage。我将依次讨论每个成分的工作方式。
Purify 组件
在 C/C++ 程序中去除分解内存使用。当它发现事件比被分配时使用更多的内存,或者在它初始化之前或者释放之后使用内存,就会发布一个错误报告。Purify 还可以报告内存泄漏――比如,当一个程序在丢失内存跟踪之前不能释放一个或者更多的内存板块时。尤其是在 Java™ 和 Microsoft .NET 程序中,Purify 能够帮助您识别使用内存并且没有将它释放的程序区域,这是另一种类型的内存泄漏。
对于 C 和 C++ 程序 (而不是 Java 或者 .NET), Purify 通过在这个程序执行中的每一个内存访问周围插入额外的指令来工作。这叫做仪表化。当您运行这个仪表化程序时,它将正常运作,进行与平时一样的操作。但是,Purify 在里面,可以检查问题。如果这个程序从还没有被初始化的内存中读取,或者读取或者改写已经被释放或者仍然存在于分配区域之外的内存,您将看到一个 Purify 错误报告。
有些类型的内存访问错误 (比如使用一个 NULL 指示器) 将会导致一个程序完全崩溃。这是一个很容易就可以辨认出的一个错误――您可以用一个正规调试器来找到它。Purify 可以让您看到更多潜伏的内存错误类型,它们可能出现在程序开起来似乎运转正常的情况下。这个特殊的功能在程序中可以产生正确的答案,您的测试可以通过,但是仍然可能存在内存错误。
例如,一个逻辑性的瑕疵可能在只有99条被分配时已经产生100条的错误。这种错误可能不会导致您的程序崩溃或者您的测试失败,但是仍然存在内存崩溃的危险。某天当潜在的内存错误由于一个不正确的操作超出了内存的范围,那么将导致系统崩溃,这将导致客户的不满意。在项目的早期,Purify 就能够很容易的发现这种类型的错误。
对于 Java 和 .NET 程序,当您的项目仍然在使用本应该已经释放的内存时, Purify 能够帮助您识别出来。这种类型的内存泄漏将会导致您的程序越来越大,运行越来越慢,最终耗尽内存。
Quantify 组件
Quantify 是 PurifyPlus 中进行分析的组件。它适用于 C/C++, Java,以及 .NET 程序。Quantify 度量并分析在程序中所花费的时间,从而识别“热点”和无效的代码。独特的 "River of Time" 显示可以直接让您找到您的程序中最浪费时间的区域。
PureCoverage 组件
PureCoverage 进行代码覆盖的分析。就像 Quantify,您可以利用它应用在您的 C/C++, Java, 以及 .NET 程序中。利用 PureCoverage,您可以确保测试您的整个程序。毕竟,您没有进行测试的代码的质量是未知的。因为您的测试并不报告它的错误或者健康状态。没有测试到的错误将会“逃离”进入释放,找到并修复它们的成本将十分昂贵。在发布版本之前识别测试漏洞,填充并找到这些错误,成本会低得多。
此外,很重要得一点是, Purify 只在运行测试的过程中对部分的程序进行错误的检验。如果您在测试覆盖范围中有漏洞,那么您在 Purify 错误检验中仍然会有漏洞。这是使用 PureCoverage 另一个很好的理由。
开发人员和测试人如何使用 PurifyPlus
开发人员和测试人员使用工具的方法是不同的。一个开发人员更想要交互的,图解的并带有“挖掘”性能的结果,然后 PurifyPlus 将它交付。而测试人员更喜欢用报告中的日志文档和总结报告,利用它们捕捉结果。PurifyPlus 也可以产生这样的结果。在这个部分中我将分别描述开发人员和测试人员利用 PurifyPlus 组件优化质量的方法,还将讨论您将从中获得的好处。
开发人员使用 Purify
开发人员可以用两种方法来使用 Purify。首先,当您遇到一个程序错误或者看起来是与不适当使用内存相关的缺陷时,您可以把它当作一个程序调整工具来使用。当内存被毁坏、不适当地使用,或者泄漏时,Purify 能够帮您识别所有不正当行为。这样看来, Purify 像一个医生:当您生病需要诊断治疗时可以求助于它。
但是开发人员还有另外一种使用 Purify 的方法:像作家利用拼写检查器一样,找到并去除您没有意识到的错误。有规律地使用 Purify,您可以在程序崩溃或者其它明显疑问的行为发生之前,找到内存的错误使用并修复它。(如果您在检验之前找到并修复了这个错误,它还会有影响吗?)
有些程序设计部门使用 Purify 的方法是,将它作为源代码中的自动步骤来控制过程。在开发人员的检入代码被允许进行测试之前,必须用 Purify 来进行测试。如果存在 Purify 错误报告,这个变更是不能继续进入到这个构架的。这样可以使构架保持健康,并不至于开发人员陷入困境中。毕竟,您并不希望成为引入一个变更而导致所有测试崩溃的人。这样看来,Purify 就像维他命或者锻炼:您可以每天使用来保持您代码的健康,这样一来这些问题就可以掌控之中。
开发人员使用 Quantify
测试人员或者测试工具可以从较高的层面上告诉您系统性能并不充分,但是找到并修复这个潜在问题的任务将落到开发人员身上。这就是 Quantify 组件参与进来的位置。Quantify 重点突出了您代码中的 "热点",比如运算法则需要改良的位置,如果链接列表应该是一个哈希表,或者什么地方应该使用缓存,以避免不必要的重新计算。
Quantify 可以用来比较您程序的两种趋向,这样您可以清楚地看到您做出代码变更时所表现的不同性能。这样您可以利用真实的代码而不是猜测来对您的性能进行最优化操作。对于 C 和 C++ 程序,Quantify 利用不变的定时数字,这样性能数据就不会受到外界因素的影响,比在测试机上加载。这意味着您可以更可靠地比较这两种趋势,度量与只使用度量“运行时间”工具相比较时地良好性能差别。
除了性能分析之外,另一种使用 Quantify 的方法是获取对程序逻辑和操作更好的理解。Quantify 的 "River of Time" 展现了一个图示,显示了程序的功能是如何调用对方的。您可以利用它来跟踪程序逻辑,并可以查看子系统之间的相互关系。有时最有价值的见解来自诸如"我并不希望这个子系统来调用那个子系统。" 之类的惊喜。Quantify 的调用图示向您显示了将会发生什么――如果它确实您所期望的不匹配,那么您就学习更多的相关知识。
开发人员使用 PureCoverage
开发人员通常负责创建单元测试,有时负责功能测试。这些测试的目的之一是在项目中特定区域中运用所有的。您可以手工检查源代码并编写您认为可以覆盖整个项目的测试案例,但是这并不是可靠的或者有效的开发测试的方法。您需要一个像 PureCoverage 一样的代码覆盖工具来告诉您:您确实在这个项目的特定区域运行所有的循环和条件。记住:未测试的代码很可能就是有疑问的代码!
一旦您创建了完全运行目标代码的单元测试,那不意味着您已经完成了编写测试。因为一旦下面的代码变更,您的测试就不可避免地会落后。它们不会运行后来引进的新特征或者不同的代码路径。您可以通过利用 PureCoverage 来有规律地分析这个测试覆盖并在特定子系统的覆盖水平寻找漏洞。早一点发现比晚点发现要好得多:如果您在一个发布版本周期的晚期遇到了不充分的覆盖,您将比其他人更晚编写测试。
当编写测试时,PureCoverage 还有另一个好处:它将告诉您何时应该停止。如果过度的测试一个功能区域或者子系统是没有好处的。如果您根据观察来编写测试,而不是利用像 PureCoverage 一样的度量工具,您将在测试创建上过分投资,并且不能得到任何额外的质量回报。PureCoverage 可以告诉您什么时候是最为合适的,帮助您节省时间和资金。
PureCoverage 对开发人员最后一个利益是,它与 Purify 的使用相结合,像一个猎手一样可以保持这个项目不受内存错误使用的影响。记住 Purify 只执行您在测试过程中实际执行的代码中的内存错误的检验。如果您的测试没有运行完所有的代码,那么您仍然不能在那些区域感受到 Purify 给您带来的好处。
测试人员使用 PureCoverage
一个测试套件只是与它所包含的测试质量有同样的性能。那看起来很明显,但是仅仅是负担着重复的操作。如果它不能真正运行这个项目,就没有必要花费时间和资金来运行这个测试套件,即使能够通过它所有的测试。如果来自这个测试套件的结论不能真实地告诉您这个项目的质量,那么您只是在浪费时间和资源。
一种度量测试质量的方法是,了解它们所运行的这个项目的区域以及(更为重要的是)它们所错过的区域。只有了解了您的测试所覆盖的范围和漏洞,您才能够判断出测试结论的价值。没有工具,测试中的漏洞是很难识别的――一个测试的失败或者崩溃是很显然的,然而测试中的漏洞确是隐蔽的。如果您不度量您测试的覆盖范围,您会继续运行您的测试并看到它们都通过测试,但是从来不会知道您的覆盖水平(因此这个测试运行的价值)正在恶化。
PureCoverage 可以度量您的测试覆盖范围,并可以显示漏洞。它可以产生单线水平的报告;但是对于测试人员来说,在文档或者子目录水平通常是最容易捕捉、总结,并趋向覆盖数据的。这样可以识别在项目整个运行时间中覆盖较少范围的区域,可以显示测试的什么位置需要按行展开有代码变更和增添新特征的区域。
测试人员使用 Purify
从测试人员或者测试经理的角度来看, Purify 是他们梦想的工具,因为它可以让您从您完成的工作中获得更多的价值。毕竟,您已经拥有运行这个项目的测试,因为它让您可以从您正在从事的工作中获得更多的价值。毕竟,您已经拥有了运行这个项目的测试,验证了它的正确性,报告了它的质量。利用 Purify 运行那些测试,您可以使它们执行双份的任务。也就是说,当您的测试忙于执行通常所执行的同样的工作时,您还可以利用 Purify 来监控这个程序的执行来检测和报告内存的使用错误。
正如上面所提到的,许多内存使用错误都是潜伏的:程序似乎在正常地运行,即使它所面临着内存崩溃或者错误行为的危险。十分普遍地情况是,测试环境并没有最终的产品环境复杂,因此即使测试都通过了,程序也能够包含一个在发布版本后即将引起严重破坏的内存崩溃性的错误。Purify 可以通过同时检查内存访问错误来对您的现存正确性测试增加价值。
这里是另一种使 Purify 成为梦想工具的方法:它可以报告出错误,以完全或者简单的方式。有些工具生成出数据后,您需要花很多时间评审或者解释或者用图示表示出来,以查看结果。但是 Purify 并不是那样的。Purify 可以识别您所测试程序中的真实错误,并向您指出正确的。Purify 有两种类型:它们被用黄色的“警告”图标标出,那些红色的是“错误的”表示。“错误”类型很明显反映了这个程序逻辑中的缺陷: Purify 报告了一个程序的错误,那也正是您所想要的。
因为 Purify 对内存使用错误的分析是如此的彻底和完全,因此,即便在测试运行中 Purify 没有报告任何错误,它仍然也是很有价值的。当 Purify 不报告任何错误时,意味着这个程序(如测试的那样)并没有那些错误。这是一个好消息,即这是一个关于被测试项目高质量的正面陈述。
理所当然的是,这仅仅运用于 Purify 所发现的内存错误的类型,以及您的测试运用这个程序的方法。在这个程序中仍然可能存在内存错误,可能随着不同的代码路径发生,或者使用没有被测试的数据模型。
这就是为什么在测试中识别漏洞时,使用 PureCoverage 与使用 Purify 同样重要。如果整个测试套件运用这个程序时不能真正完成它的引导,那么一个通过 Purify 的等级也并没有很大意义。就像一个交通警察, Purify 可以仅仅报告在有人监控时所发生的错误行为。PureCoverage 可以让您识别测试中的漏洞,因此您可以填充这个漏洞并使用 Purify 来诊断问题。
测试人员使用 Quantify
测试不仅仅是与正确性有关的。项目质量的另一个因素是执行。即使这个软件通常运作地很好并且给了您正确的答案,如果它慢得让人难于忍耐您也不可能拥有高质量的产品。并不明显得是,性能可以从一个构架到另一个构架或者从一个发布版本到另一个发布版本发生变更,比如您开始时可以有很好的性能,但是也可能在中途的某个位置遗失了好的性能。
Quantify 让您能够度量项目的性能特征。您可以利用这个数据在整个过程中跟踪结果,辨认出从一个构架到另一个构架或者从发布版本到发布版本的性能。例如,想想您已经拥有一个服务器上测试,并且这个测试将带有标准数据包和事务序列。您可以利用 Quantify 来度量这个测试的性能,并且您可以在项目进展时对性能进行跟踪。证实新特征和代码变更并没有对整个性能产生严重影响是十分重要的。利用 Quantify 的 "图像偏差 1 " 特性,您可以利用函数调用关系图和 River of Time 来比较先前和当前的趋势,并重点突出新热点和时间陷阱。
如果一个测试套件含对 Quantify 度量特征的了解,它甚至能够缩小焦点来消除不重要的因素。例如,如果这个服务器要花费很长时间来启动,那么对于许多服务器应用软件来说就不重要:重要的启动之后事务性能的运行速率。一个 Quantify 知晓的测试可以使带有标准数据和事务的服务器“预热”(来填充这个缓存),然后使 Quantify 在完成所有事务之后开始数据交换。通过聚集连续事务的时间数据,这个数据可以消除一次的启动成本,对这个系统的核心性能是否以及怎样从一个构架到另一个构建或者一个发布版本到另一个发布版本进行变更有一个清晰的概念。
结论
事实是:开发人员和测试人员的想法不同。他们使用工具的方式也不同。他们的共同点是对质量的关注。这两种角色都能够从使用 Rational PurifyPlus 的使用过程中获得利益,因为它既是开发人员也是测试人员的工具――它是一个质量工具。
-
成功的 Web 应用系统性能测试
2008-4-06
性能测试是 Web 应用系统的一项重要质量保证措施。在现实中,很多 Web 性能测试项目由于性能测试需求定义不合理或不明确,导致性能测试项目不能达到预期目标或进度超期。本文针对 Web 应用系统的技术架构和系统使用特点,探讨如何有效实施性能测试过程,并重点介绍如何分析获得合理的性能测试需求,最终对 Web 应用系统性能进行科学、准确的评估。
基于Web服务器的应用系统由于提供浏览器界面而无须安装,大大降低了系统部署和升级成本,得以普遍应用。目前,很多企业的核心业务系统均是Web应用,但当Web应用的数据量和访问用户量日益增加,系统不得不面临性能和可靠性方面的挑战。因此,无论是Web应用系统的开发商或最终用户,都要求在上线前对系统进行性能,科学评价系统的性能,从而降低系统上线后的性能风险。
在很多性能测试项目中,由于不能合理定义系统的性能测试需求,不能建立和真实环境相符的负载模型,不能科学分析性能测试结果,导致性能测试项目持续时间很长或不能真正评价系统性能并提出性能改进措施。
本文在总结许多Web应用系统性能测试实践经验和教训的基础上,从与性能测试工具无关的角度介绍Web应用系统性能测试的方法和实施过程,以及如何定义合理的性能测试需求。
性能测试:通过模拟大量浏览器客户端同时访问Web服务器,获得系统的性能数据。
虚拟用户:模拟浏览器向Web服务器发送请求并接收响应的一个进程或线程。
响应时间:浏览器向Web服务器提交一个请求到收到响应之间的间隔时间。
思考时间:浏览器在收到响应后到提交下一个请求之间的间隔时间。
请求成功率:Web服务器正确处理的请求数量和接收到的请求数量的比。
吞吐量:单位时间内Web服务器成功处理的HTTP页面或HTTP请求数量。
在线用户:用户通过浏览器访问登录Web应用系统后,并不退出该应用系统。通常一个Web应用服务器的在线用户对应Web应用服务器的一个Session。
并发用户数:Web服务器在一段时间内为处理浏览器请求而建立的HTTP连接数或生成的处理线程数。当所有在线用户发送HTTP请求的思考时间为零时,Web服务器的并发用户数等于在线用户数。
Web应用系统的前端为浏览器,后台为Web服务器(如Apache,Microsoft Internet Information Server),浏览器和Web服务器之间的交互基于HTTP协议。HTTP协议本身是无连接的,Web服务器通过Session机制来建立一个浏览器所发出的先后连接之间的关联。通过实验证明,当浏览器客户端在首次访问Web服务器后,如果该浏览器客户端不发送后续请求,服务器维持该浏览器客户端的Session变量所消耗的系统资源非常小。
标准的Web应用系统性能测试过程包括确定性能测试需求,开发性能测试脚本,定义性能测试负载模型,执行性能测试和形成性能测试报告。本章将分别介绍上述过程,并通过举例说明如何完成每一环节。
科学定义Web应用系统性能测试需求对一个成功的性能测试非常重要。通常,Web应用系统的性能测试需求有如下两种描述方法。
2.1.1 基于在线用户的性能测试需求
该需求描述方法主要基于Web应用系统的在线用户和响应时间来度量系统性能。当Web应用系统在上线后所支持的在线用户数以及操作习惯(包括操作和请求之间的延迟)很容易获得,如企业的内部应用系统, 通常采用基于在线用户的方式来描述性能测试需求。以提供网上购物的Web应用系统为例,基于在线用户的性能测试需求可描述为:10个在线用户按正常操作速度访问网上购物系统的下定单功能,下定单交易的成功率是100%,而且90%的下定单请求响应时间不大于8秒;当90%的请求响应时间不大于用户的最大容忍时间20秒时,系统能支持50个在线用户。
2.1.2 基于吞吐量的性能测试需求
该需求描述方法主要基于Web应用系统的吞吐量和响应时间来度量系统性能。当Web应用在上线后所支持的在线用户无法确定,如基于Internet的网上购物系统,可通过每天下定单的业务量直接计算其吞吐量,从而采取基于吞吐量的方式来描述性能测试需求。以网上购物系统为例,基于吞吐量的性能测试需求可描述为:网上购物系统在每分钟内需处理10笔下定单操作,交易成功率为100%,而且90%的请求响应时间不大于8秒。
在确定Web应用系统性能测试需求后,就要根据性能测试需求中确定的功能开发性能测试脚本。比如,针对前面定义的网上购物系统的性能测试需求,将开发下定单功能的性能测试脚本。
性能测试脚本是描述单个浏览器向Web服务器发送的HTTP请求序列。每个性能测试工具(如IBM Rational Performance Tester, LoadRunner)所提供的测试脚本语法是不同的。测试人员利用性能测试工具可从头手工编写测试脚本,也可以通过录制浏览器和Web服务器之间的网络通信数据而自动形成测试脚本。
任何性能测试工具都不能保证录制形成的性能测试脚本的正确性,测试人员应通过在单用户下运行性能测试脚本对其正确性进行验证。测试脚本不正确的一个重要原因就是脚本的数据关联不正确,也就是并没完全建立一个测试请求和前面的响应内容之间的关联。测试脚本HTTP请求和响应之间的数据关联是否正确的一个重要标准是单用户运行脚本,脚本能完成期望的功能。
在完成性能测试脚本的数据关联后,需要对脚本进行参数化,也就是把脚本中的某些请求数据替换成变量,变量的值来于一个独立的数据文件,从而保证在多虚拟用户运行脚本的情况下,每个虚拟用户所提交的数据是不同的。
此外,为了测试Web应用的可靠性,还需要对请求所收到的响应进行验证(比如验证响应的HTTP返回码或验证响应的内容),便于性能测试完成后统计请求成功率。
性能测试负载模型定义了测试工具如何向Web应用系统提交请求,包括向Web应用系统发送请求的虚拟用户数,每个虚拟用户发送请求的速度和频率。针对前面介绍的网上购物系统的性能测试需求,在性能测试工具中定义的性能测试负载模型应包括如下信息:
虚拟用户数:性能测试不仅仅是执行一次,而且每次执行时虚拟用户数也不固定,因此在性能测试负载模型中定义的虚拟用户数将在测试执行时进行设置。
虚拟用户发送请求的思考时间和迭代次数:虚拟用户发送请求的思考时间长短是决定Web应用系统负载量的重要因素之一,而迭代次数将决定性能测试的执行持续时间。对基于在线用户的性能测试需求,将基于录制脚本时记录的思考时间,而且由于现实中不同用户访问系统的思考时间不同,可把思考时间设置为在一定范围内的随机值。对于基于吞吐量的性能测试需求,将把思考时间设置为零,此时Web应用系统的在线用户数量将等于并发用户数。同时,为了避免性能测试压力的随机性,将增加请求的迭代次数来增加测试执行持续时间,从而获得系统在稳定压力下的性能数据。
虚拟用户启动模式:在现实中,Web应用系统的用户不太可能同时做相同的操作,因此为了让Web应用系统所承担的压力随时间均匀分布,建议虚拟用户依次启动,同时也避免大量用户同时登录造成系统阻塞。以10个虚拟用户模拟下定单为例,可设置每个虚拟用户间隔30秒启动,这样10个虚拟用户可在5分钟后完成启动,并保证10个虚拟用户不会在同一时刻下定单,从而更符合实际情况。
执行性能测试是指通过多次运行性能测试负载模型,获得系统的性能数据。在执行过程中,需利用测试工具、操作系统、系统软件(如Web Server或DB Server)提供的资源监控手段对资源进行监控和分析,帮助发现资源瓶颈,并在系统层面进行优化。同时,还需对应用进行性能分析,帮助定位应用代码中的性能问题,切实解决系统的性能问题。
性能测试项目的最后阶段就是向相关人员提交性能测试报告,汇报性能测试结果。在向相关人员汇报性能测试结果时,并不是性能测试报告越丰富、性能数据越多越好。好的性能测试报告是能准确、简单地传递性能测试结论,而不需太多的技术细节。
针对基于在线用户数的性能测试需求,可通过下图总结性能测试结论。其中横轴是在线用户数,纵轴是响应时间,如40在线用户访问网上购物系统时,90%的下定单请求响应时间不超过10秒。
图一:在线用户数和响应时间时间的趋势图
针对基于吞吐量的性能测试需求,可通过下图的曲线来描述性能测试结果。以网上购物系统为例,下图描述下定单的并发用户、下定单响应时间以及吞吐量(服务器每秒处理定单笔数)之间的关系,从而快速判断系统是否能满足性能测试需求。从下图中可看出,并发用户增加,请求的响应时间也增加。服务器的吞吐量是先随并发用户数增加而增加,当吞吐量到达一定峰值后,再增加并发用户数,吞吐量会减少。原因在于当并发用户数少时,向Web服务器提交的请求量不大,服务器处理能力还有富余,所以吞吐量逐步增大;但当并发用户数超过某一值时,由于向服务器提交的请求太多,造成服务器阻塞,反而导致吞吐量减少。
图二:响应时间、吞吐量和并发用户数的趋势图
前一章介绍了Web应用系统的性能测试过程,确定性能测试需求是整个性能测试的起点和成功的重要因素。性能测试需求定义得过高,虽然确保系统上线后能满足性能需求,但可能会造成硬件资源的浪费;性能测试需求定义得过低,系统上线后可能会出现性能问题。如何通过分析系统上线后可能的用户访问行为,来获得合理的性能测试需求指标呢?
假设现有一个基于Web的办公自动化系统(简称OA系统),该系统提供公文收发和查询功能。在部署该系统前,将对该系统进行性能测试。下面将详细介绍如何分析该OA系统的使用情况,定义合理的性能测试需求。
在线用户数量是指在特定时间区间内,有多少用户访问Web应用系统(对应到Web服务器的Session数),根据系统可能访问用户数以及每个用户访问系统的时间长短来确定。
对于将要部署的OA系统,通过分析获得该系统有8000个注册用户,基本上所有的用户每天(8小时工作时间)都会访问OA系统,平均在线时间(从登录OA系统到退出OA系统之间的时间间隔,也可以是多次在线时间的合计)为12分钟,那么该OA系统的平均在线数(也就是Web应用Session变量数)为200个(8000 * 0.2 / 8),假设峰值在线用户数是平均在线用户数的3倍(该倍数可根据实际情况调整),则性能测试需求的在线用户数为600。
由于时间和资源限制,不可能对Web应用系统的所有功能进行性能测试,而是从业务的角度(如某一功能操作的用户多)和技术的角度(如某一功能虽然访问用户不多,但内部处理逻辑复杂或处理数据量大)来选择Web应用系统的特定功能作为性能测试用例。
以OA系统为例,由于所有用户都经常公文查询功能,因此确定的性能测试用例为公文查询。
响应时间的快慢直接影响了系统使用用户的满意度,采用平均响应时间来描述系统系统性能测试需求是不科学的,因为无法直接和客户的满意度挂钩。而且,在做性能测试,如果某一请求的响应时间过长或过短,将导致平均响应时间和实际情况偏离。
以OA系统为例,定义的响应时间需求为:90%(该百分比和要求的系统用户满意度相关)的查询请求响应时间不超过8秒(该时间可根据实际情况确定)。
单位时间内Web应用系统需处理多少笔特定的交易可通过统计获得。以OA系统为例,假设每个用户每天(一天按8小时计算)平均会查询公文4次,那OA应用的Web服务器平均每分钟要能处理8000 * 4 / ( 60 * 8 ) = 66.67笔查询公文交易,考虑到峰值因素,要求每分钟能处理66.7 * 3=200笔查询公文交易。
通过前面的分析,能明确定义合理的性能测试需求。OA系统性能测试需求定义如下:
基于在线用户数的性能测试需求:600个在线用户按正常操作速度访问OA系统的查询公文功能,所有查询请求的成功率是100%,而且90%的查询请求响应时间不大于8秒。
基于吞吐量的性能测试需求:OA系统在每分钟内需处理200笔查询公文操作,交易成功率为100%,而且90%的请求响应时间不大于8秒。
Web应用性能测试项目成功的关键不在于性能测试工具,而在于有效的性能测试分析方法和实践。只有切实掌握性能测试需求分析方法,性能测试实践经验,才能保证一个Web应用性能测试的成功。
- 请访问 IBM developerWorks 中国网站 Rational 专区 能得到更多关于 IBM IBM Rational 产品的文章、教程和其他参考资源。


杨敏强,IBM Rational 软件工程师。
- 请访问 IBM developerWorks 中国网站 Rational 专区 能得到更多关于 IBM IBM Rational 产品的文章、教程和其他参考资源。
-
IBM Rational Performance Tester 和 HP Mercury LoadRunner 的比较
2008-4-06
本文概要介绍 IBM Rational Performance Tester (简称 RPT)和 HP Mercury LoadRunner (简称 LR)两个性能 / 压力测试工具,主要从脚本开发,场景构建与配置,性能监控,测试结果分析几个方面,对 LR 和 RPT 的使用做了详细的对比分析,并根据 IBM Lotus Form 系统测试团队从 LR 到 RPT 的迁移的工作经历中总结了一些 RPT 的一些实用技巧。对于那些需要从 LR 工具切换到 IBM RPT 的测试人员的测试技术的平滑过渡,具有较强的借鉴意义。
LoadRunner 是一种适用于各种体系架构的自动负载测试工具,通过模拟实际用户的操作行为和实施实时性能监测,来帮助用户排查和发现问题。相比于 RPT, LR 能支持更广范的协议和技术,适应面很广,为用户的特殊环境提供特殊的解决方案。LR 的组件很多,其中最核心的组件包括:
- Vuser Generator(VuGen) 用于捕获最终用户业务流程和创建自动性能测试脚本
- Controller 用于组织、驱动、管理和监控负载测试。
- Load Generator 负载生成器用于通过运行虚拟用户生成负载。
- Analysis 有助于您查看、分析和比较性能结果。
IBM Rational Performance Tester(简称 RPT)也是一款性能测试工具,适用于基于 Web 的应用程序的性能和可靠性测试。Rational Performance Tester 将易用性与深入分析功能相结合,从而简化了测试创建、负载生成和数据收集,以帮助确保应用程序具有支持数以千计并发用户并稳定运行的性能。
- RPT 是针对 Web 应用程序的性能测试工具,基于 Windows 和 Linux 的用户界面,使用基于树型结构的测试编辑器提供高级且详细的测试视图。
- 提供不同用户数的灵活的模拟,支持将 Windows 和 Linux 用作分布式负载生成器,使用最小化的硬件资源实现大型、多用户的测试。
- 支持使用自定义 Java 代码的灵活测试定制。




回页首
LR/RPT 的脚本的开发过程通常都是采用录制 + 定制的模式。首先通过对典型业务逻辑的录制,完成脚本中的基本业务的框架,然后针对录制结果,通过参数化,数据关联,增加逻辑控制等方式加强脚本的适应性来满足特殊的业务需求。
- LR:直接生成面向过程的运行代码
LR 通过对基本业务的录制,VuGen 将生成的 Vuser 函数(也称作 LR API)并将他们插入到脚本中。在实践中,LR 脚本就是由这样的 Vuser 函数和一些定制代码组成的。对于基于 Web(HTTP/HTML) 的应用程序的测试,多数用户选择基于 C 语言的 LR 脚本,显然,这种 LR 脚本是一种面向过程的脚本,开发者可以对最终运行的脚本进行直接的修改与调整。对于开发者来说,这种 LR 脚本的开发方式比较灵活。相应地,这项工作,对于开发者的编程基础,尤其是 C 语言和 LR API 的了解,要求都比较高。
- RPT:录制结果经过“翻译”生成最终的运行代码
与 LR 不同,RPT 的脚本录制过程可以拆分成两步。如图 1 所示,第一步,RPT Recorder on RAC 负责记录用户的所有 HTTP 请求,生成一系列的 Trace 文件。Trace 文件记录了用户与服务器的交互过程。第二步,当用户完成脚本的录制过程之后,RPT Test Generator 能够根据 Trace 文件“翻译”一遍,生成最终运行的测试脚本。
这种生成临时 Trace 文件的好处是用户可以随时依据该 Trace 文件生成新的测试脚本,然后再对脚本进行测试场景定制,而不用对同一个操作过程做多次录制操作。
图 1. RPT 脚本的录制和生成架构
录制业务流程时,
LR/RPT生成一个包含录制期间用到的实际值的脚本。假设用户要使用不同于录制内容的值执行该脚本的操作时,就需要用参数替换已录制的值。这被称为脚本参数化。脚本的参数化可以简化脚本,同时增强脚本适用性。对于 LR 和 RPT 脚本,参数化过程类似,都是定义参数,为参数指定属性或者数据源的过程。但是在 LR 中,只有函数中的参数才能参数化,除此之外,其他字符串不能进行参数化。RPT 的参数化过程同样简单(以替换用户登录密码为例来说明),首先,选中需要进行参数替换的请求页面,如图 2 所示,选中左侧的登陆请求页面。在其右侧的 Test Data 中则显示与该请求页面相关的所有数据信息,脚本录制人员可以用其他值代替图 2 中的 password 变量。
图 2. RPT 脚本参数化
数据关联类似于参数化,可以简化脚本,适应企业应用中需要动态数据的情况。默认情况下,LR 和 RPT 都能做到一些基本的数据关联,但是由于 HTTP 请求之间关联的复杂性,需要用户手动做一些数据关联。数据关联包含三个步骤,一是定义哪个录制的值需要被关联(替换);二是定义数据源。三是定义被关联的数据与数据源之间的关联关系。
LR 的数据关联过程如下:
lr_save_XXXX(value,dataSource)语句将数据源的值保存到参数dataSource中;用lr_eval_XXXX(dataSource)语句替换被关联的数据。RPT 中如果需要自己定义关联,则在 HTTP 请求中的 URL 中或者 Data 中选择需要创建关联的部分,然后右键选择替换对象。其中替换对象可以是脚本中已经建立好的引用(这里的引用就是一种用户自定义的数据源),或者 RPT 自带的数据源(例如时间戳对象),或者是
Custom Code( 下节介绍 )。图 3 中浅紫色的部分是已经被关联的 URL,运行测试时该部分将由被引用的 URL 值来替换该 URL。
图 3. RPT 数据关联
Custom code 是 RPT 独有的概念。尽管 RPT 脚本开发过程中,用户可以直接在 UI 层面达到对脚本的定制,但是这种定制能力毕竟有限。将定义好的 Custom Code 通过 UI 穿插到脚本之中,从而为 RPT 录制的脚本提供充足的扩展能力来保证其灵活的定制性。Custom code 本质上就是一个 Java 类。Custom Code 需要实现
com.ibm.rational.test.lt.kernel.custom.ICustomCode2接口,并实现该接口中的如下方法:public String exec(ITestExecutionServices tes, String[] args)
ITestExecutionServices tes参数是 Test Container 中的一个实例 , 使用它可以访问 Test Container 运行态一些服务。String[] args参数是我们定义 Custom Code 时定义传入的参数数组。该方法的主体就是基于传入的信息进行业务逻辑处理代码,然后将处理结果(一个字符串)返回,其返回的字符串可以被后续的请求引用。Custom Code 是一个纯 Java 的类,所以具有 Java 编程经验的人都可以根据业务需求编写自己的 Custom code。
性能 / 压力测试过程中,通常都需要为某些测试提供大量的测试数据。LR 和 RPT 都提供了数据池功能,即是将一个数据文件作为参数值赋给一个参数。
LR 中,用户可以指定该文件的多个数据以何种方式赋值到该参数中。LR 提供三种选择,顺序,随机,唯一。前两种比较容易理解,最后一种是指每个虚拟用户都从该文件中取不同的值作为参数值,如果该数据池不足够大,所有的备选值都已经被取出过一次,即该数据池资源被用尽时,LR 报错。
在 RPT 中,用户只能顺序从数据池中读入测试数据。RPT 的数据池是以 XML 格式存储的,并且在测试开始时,将数据池中的所有数据都加载到内存中,这样的实现模式不利于测试中使用大数据量。不过灵活的 Custom Code 功能可以弥补这方面的不足。对于大量的测试数据,可以通过自定义 Custom Code 来实现 On Demand 的数据读取和加载。
图 4. RPT 数据池
LR 脚本大部分是基于 C 语言的,因此 C 语言中的流程控制语句(例如判断、循环等)都可以加入到 LR 脚本中。RPT 的流程控制操作可以通过 UI 界面轻松进行,它提供了灵活的流程控制模式,包括 IF 条件控制结构,和 LOOP 循环结构。
1. IF 条件控制结构
在 RPT 脚本中,可以将一部分连续的页面或者 HTTP 请求放到一个 IF 条件中去,然后由判断条件来确定 IF 结构中的页面或者 HTTP 请求是否被执行。其判断条件可以是 RPT 自动参数化后的参数,也可以是 Custom Code 的返回值,或者是数字、字符串等。
图 5 是添加了 IF 条件后的脚本,包含了为 IF 语句设置判断条件的配置界面。
图 5. RPT IF 条件控制结构
同样,RPT 也支持 IF-ELSE 的结构。
2. LOOP 循环结构
RPT 中的另外一种流程控制结构就是 LOOP 结构,如图 6 脚本中,将所有的页面放到了一个 LOOP 结构中,然后可以通过指定循环次数来确定其中的脚本循环执行多少次。
图 6. LOOP 控制结构
这里所说的全局信息,实际上是脚本运行时,LR/RPT 产生的内部数据,例如:当时的运行时间,Vu 所在用户组组名,迭代编号等。在 LR 中,所有的全局信息作为特殊的参数类型,供脚本开发者使用。例如 : 如果一个变量为
Group Name类型,则该变量的值即为当前用户所在的用户组的组名。RPT 中的全局信息,存在
IDataArea对象中。IDataArea 对象包含三个方面的信息,分别是“Test Data”、“Virtual User Data”、“Engine Data”,这些信息都可以通过 Custom Code 来获得。Custom Code 的实现需要继承
ICustomCode2类,并实现该接口的核心方法“public String exec(ITestExecutionServices tes, String[] args)”,该方法的第一个参数就可以获得IDataArea对象,然后获得全局信息。同时用户也可以向IDataArea对象中添加信息,提供给测试脚本的其它地方使用。LR 用户可以指定脚本执行期间的错误的处理方法。默认情况下,当脚本执行出现错误,脚本将退出执行。用户也可以配置运行设置指示当
Vuser出现错误时仍继续执行脚本。除此之外,用户还可以在脚本中加入lr_error_message函数,便于用户对日志的分析。RPT 中,当脚本运行出现错误,脚本将继续执行 , 可能后续
会出现很多错误。LR VuGen 可用作常规文本编辑器。您可以在其中打开任何文本文件并进行编辑。当重播期间在输出窗口中显示错误消息时,您可以双击该错误消息, VuGen 将使光标跳到导致问题的测试行。您还可以将光标置于错误代码上并按 F1 键,查看该错误代码的联机帮助 .
RPT 在运行完一个测试之后,会产生相应的测试日志,如果在测试过程中发生任何错误,RPT 会以“Message”的形式提示出该请求发生错误。如图 7 中的测试日志中被选中的 Message 表示该 HTTP 请求在引用前面的关联值时发生错误。
图 7. RPT 错误日志




回页首
脚本只是定义了某些用户的操作步骤,而一个场景则包含了有关如何模拟实际用户的所有信息。LR 和 RPT 的场景构建过程比较类似,只是对脚本循环的控制,分配负载生成器等配置上略有差别。
LR 中,Controller 组件负责场景的创建。您需要在一个场景中添加一个或多个脚本,并为每个脚本分配相应的 Vuser 组。然后,您可以为每个 Vuser 组分配多个虚拟用户,指定模拟该用户组的负载生成器。图 8 中,负载生成器即为本机,即负载生成器跟 Controller 是同一台机器,如果该处配置成其他计算机的 IP 地址,那么该用户组的负载模拟将由其他计算机完成。LR 中不能通过 Controller 指定一个脚本执行与否的概率,但是可以通过 C 语言开发,完成随机调用脚本的功能。Runtime-Setting 包含了所有针对该场景的一些附加配置,如脚本循环次数,等待时间,网络模拟等。
图 8. LR 场景创建
RPT 中测试场景,是通过“Schedule”来组织的。Schedule 通过用户组、循环控制、随机选择器等功能部件来组织测试脚本使其满足实际场景。用户组则由循环控制或者随机选择器,再加上测试脚本等元素组成。循环控制用来控制其下的测试脚本需要循环执行的次数。随机选择器是为了实现在多个测试脚本中随机选择一个来执行。可以为随机选择器指定权重,通过权重值来决定在多个随机选择项中某项被随机选中的概率大小。图 9 是一个 RPT 创建场景的例子,其中“Schedule Element Details”提供了对 Schedule 的丰富配置功能,与 LR 中的 Run-Time 配置功能类似。
图 9. RPT 场景创建
RPT 的负载生成器配置也比较简单,首先选中要放到其它 RPT 主机上进行模拟的 User Group,然后在其配置界面中选中“Run this group on the following locations”,在其中添加远端的 RPT 主机信息。
图 10. RPT 负载生成器配置




回页首
LR 和 RPT 内部都集成了一些实时监控器,RPT 可以对事务,Web,系统,Web 应用服务器等资源进行实时监控。LR 的监控范围更广泛一些,除了上述资源之外,还可以对网络,防火墙,Web 服务器,数据库,ERP,Java 等资源进行实时监控。无论使用那种测试工具,在自动测试过程中的任何时间,用户都可以获知系统的多种性能指标的当前值和变化趋势。
在一个测试场景中,用户需要将被监控的服务器信息加入到资源监控列表中。LR 中,如图 11 所示,从左侧资源树中选择资源种类,在右侧对应资源状态显示窗口中,右键添加被监控的服务器名称。
图 11. LR 添加被监控的服务器信息
RPT 中,图 12 所示,用户需要在 Schedule 的配置窗中的“Resource Monitoring”标签栏添加需监控的服务器。
图 12. RPT 添加被监控的服务器信息




回页首
LR 和 RPT 都提供了测试结果的多种图表以及图表之间的叠加效果,方便用户分析测试结果。LR 中测试结果图表的生成由 Analysis 组件完成。默认情况下,用户可以直接看到测试的总体概要分析,吞吐率,事务平均响应时间等图表,如果用户希望看到其他资源的监控图,可以通过添加图表完成(图 13)。“Merge Graghs”可以帮助用户将同一个测试结果中的多种资源的结果进行叠加(图 14)。“Cross Result”可以生成多次测试结果的比较分析图(图 15)。
图 13. LR 添加其他资源监控图
图 14. LR 同一次测试中多种监控图的叠加
图 15. LR 多次历史测试结果之间的比较
RPT 也为测试结果提供了直观的图表表现,默认情况下,用户可以直接看到对测试成功率的总体柱状图,整个测试过程完成的总体信息列表,测试中页面的反应时间曲线图等报告。也可以通过添加其他监控信息的方法,将其他资源的监控图叠加到当前的监控图中。
图 16. RPT 叠加其他资源监控图
RPT 也可以实现多次测试结果的比较。在 RPT 的“Test Navigator”中选择待比较的测试结果,在其右键菜单中选择“Compare”,打开“Compare Results”窗口,然后将需要做比较的测试结果添加进来,在下一步中选择要显示的报告,点击“Finish”按钮打开比较结果的显示页面。图 17 是一个测试结果的比较报告。
图 17. RPT 多次历史测试结果之间的比较报告




回页首
6 Rational Performance Tester 实用技巧
1)调整日志采样频率和粒度以适应不同的测试场景
RPT 的 Schedule 提供了测试数据的采样频率和采样粒度的配置,以适应不同的测试场景。在做长时间测试时,在 Schedule 的配置面板中的“Statistics”标签中通过适当增加日志采样间隔时间、日志级别和采样用户量,降低 RPT 的压力,避免因采样数据量过大,使内存耗尽,导致 RPT 无法响应。
图 18. Statistics 配置
在测试过程中,RPT 会记录测试中的请求数据和响应数据,以便在测试之后查看测试过程中的数据和错误信息。对于长时间测试,会产生大量的请求和响应数据,这些大量的日志信息会让 RPT 不堪重负。在 Schedule 配置部分的“Test Log”标签中提供了日志记录的级别设置,对于长时间的测试,推荐使用图 19 所示的配置,记录错误和警告信息的级别为“All”,而对于其它信息则只记录“Primary Test Actions”即可。
图 19. LOG 配置
2)通过 Custom Code 实现多条测试数据的随机读取
在 RPT 中通常采用 DataPool 的形式作为少量测试数据(例如模拟多个用户登录所用的多个用户名密码信息)的输入。不过 DataPool 的读取方式为顺序读取。如果对于输入数据需要随机读取,则可以通过 Custom Code 来实现。其实现方式可以是将测试数据存为“*.cvs”等格式文件,然后通过文件操作,并根据随机数从文件中读取内容作为测试输入数据。
3)使用超大测试数据集文件
对于在测试过程中存在少量测试数据分次作为测试输入数据时(例如模拟多个用户登录所用的多个用户名密码信息),通常采用 DataPool 的形式,但是在测试数据量较大时该方法就不再适用,因为对于 DataPool 中的数据,测试开始时就被全部加载到内存,如果测试数据量过大,这种方式会造成大量的内存浪费。
这种情况可以通过 RPT 提供的扩展功能 Custom Code 来定制代码,达到在测试过程中在需要的时候再去加载所需的内容,其实现也可以采用文件操作的方式。




回页首
本文中,我们概要介绍了 RPT 和 LoadRunner 两个性能压力测试工具,从多方面对两个工具进行详细的对比分析,并根据实践经验总结了一些 RPT 的实用技巧。通过本文,并学习链接中的网站,希望您能更快,更多的了解和使用 Rational Performance Tester 工具。
免责声明和公开声明
本文所述观点是基于作者个人对相关产品的理解,并不代表 IBM 的官方观点,IBM 不对本文中的信息负责。本文是在本人的知识范围内写成的。如果您发现有异议的地方,请与本人联系。
学习
- 访问 Rational Performance Tester 产品网页,查看 Rational Performance Tester 产品数据表。
- 查看 HP LoadRunner 产品网页。
- Rational Performance Tester 使用示范教程:“Hello World: 使用 Rational Performance Tester 发现并分析应用程序的性能问题”。
- Rational Performance Tester 产品演示,Rational Performance Tester 使用演示。
- 通过文章 “IBM Rational 助您轻松完成基于 J2EE 的 Web 应用系统的性能测试和性能优化”,了解 Rational 的自动化测试工具。
获得产品和技术
- Rational Performance Tester 试用版 软件下载。
- LoadRunner Loadruner 官方网站。


张营,软件工程师,现在 IBM 中国软件开发实验室 Lotus 测试开发中心工作,目前从事 IBM Lotus Forms 系统测试。之前从事过 IBM Workplace Collaboration Services 功能测试,自动化测试。对软件测试、协同软件有浓厚兴趣。


谷林是 IBM 中国一名软件工程师,现在 IBM 中国软件开发实验室 Lotus 测试开发中心工作,目前从事 IBM Lotus Forms 系统测试。对 Java、Web 技术和软件体系结构有着浓厚的兴趣,并在 Java 软件开发和软件测试方面有较丰富的经验。
-
上传本地文件到服务器的 LoadRunner 脚本实例
2008-1-07
昨天测试了一个上传视频的应用,要测试这个应用的性能,于是使用LR进行测试
开始录制脚本,脚本录制完成后,发现:文件内容被转换成了二进制码,存于脚本中,而不是文件的路径,相信有做过类似测试的朋友都有遇到这样一个问题,后来经GOOGLE相关资料,解决了这个问题,实现在上传文件以本地文件路径的方式,具体方法见附件
LR上传本地文件脚本.rar
(2007-12-22 15:39:59, Size: 3.78 kB, Downloads: 34) -
Loadrunner message函数详细分析
2007-11-03
Loadrunner提供了若干message函数,以在脚本回放中和脚本运行中,对外输入信息,主要的函数有:
【lr_message】
int lr_message (const char *format, exp1, exp2,...expn.);
中文解释:lr_message函数将信息发送到日志文件和输入窗口。在VuGen中运行时,输入文件为output.txt。【lr_log_message】
int lr_log_message (const char *format, exp1, exp2,...expn.);
中文解释:lr_log_message函数将消息发送到Vuser或代理日志文件(取决于应用程序),而不是发送到输出窗口。通过向日志文件
发送错误消息或其他信息性消息,可以将该函数用于调试。【lr_error_message】
int lr_error_message (const char *format, exp1, exp2,...expn. );
中文解释:lr_error_message函数将错误消息发送到输出窗口和Vuser日志文件。要发送不是特定错误消息的特殊通知,请使用lr_output_message。【lr_output_message】
int lr_output_message (const char *format, exp1, exp2,...expn.);
中文解释:lr_output_message函数将带有脚本部分的行号的消息发送到输出窗口和日志文件。【lr_vuser_status_message】
int lr_vuser_status_message (const char *format);
中文解释:lr_vuser_status_message函数向控制器或优化模块控制台的vuser窗口的“状态”区域发送字符串。它还将该字符串发送
到vuser日志。从VuGen运行时,消息被发送到output.txt。下面大家看例子:
Action()
{
int i,j,k;
char *message;
j = k = 1000;message = "信息";
lr_message("****************输出区域开始*****************");
lr_message(" lr_message %s:十进制=%d,八进制=%o,十六进制=0x%x",message,j,j,j);
lr_log_message(" lr_log_message %s:十进制=%d,八进制=%o,十六进制=0x%x",message,j,j,j);
lr_error_message(" lr_error_message %s:十进制=%d,八进制=%o,十六进制=0x%x",message,j,j,j);
lr_output_message(" lr_output_message %s:十进制=%d,八进制=%o,十六进制=0x%x",message,j,j,j);
lr_message("****************输出区域结束*****************");
for (i=1;i<6;i++)
{
k += 1000;
lr_think_time (5);
lr_vuser_status_message("第%d次:%s,十进制=%d,八进制=%o,十六进制=0x%x",i,message,k,k,k);
}
return 0;
}
例子说明:
1、message系列的函数参数格式和c语言中的printf格式是完全相同的。
2、格式化输入标志符号"%",想必大家也比较熟悉。其中%d是十进制,%o是八进制,%x是十六进制,%s是字符;还有%g、%u、%c等,自己去查。
3、回放这个脚本后,进入脚本根目录查看mdrv.log,所有输出都可以在这里找到。
4、lr_error_message回放日志中显示的是红色的字体,且显示语句所在行号;同时,如果脚本在controllor中运行时,会生成一个error信息。
5、lr_vuser_status_message会在controllor的vuser list的status列中显示,controllor每5秒刷新一次。
6、当然,也支持转义字符的使用,列表如下:
\a 铃声(警告)
\b Backspace 键
\f 换页
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\' 单引号标记
\" 双引号标记
\\ 反斜杠
\? 文本问号
\ooo ASCII 字符 - 八进制
支持的转换字符有:
%a ASCII 表示形式
%BX 大端(网络顺序)十六进制
%BO 大端(网络顺序)八进制
%BD 大端(网络顺序)十进制
%LX 小端十六进制
%LO 小端八进制
%LD 小端十进制==============================================================
此外,loadrunner还提供了在脚本中控制runtime-setting的log设置的函数。
【lr_debug_message函数组】
int lr_debug_message (unsigned int message_level, const char *format, ... );
中文解释:lr_debug_message函数在指定的消息级别处于活动状态时发送一条调试信息。如果指定的消息级别未出于活动状态,则不
发送消息。您可以从用户界面或者使用lr_set_debug_message, 将处于活动状态的消息级别设置为MSG_CLASS_BRIEF_LOG
或MSG_CLASSS_EXTENDED_LOG。要确定当前级别,请使用lr_get_debug_message。unsigned int lr_get_debug_message ( );
中文解释:lr_get_debug_message函数返回当前的日志运行时设置。该设置确定发送到输出端的信息。日志设置是使用运行时设置对
话框或通过使用lr_set_debug_message函数指定的。int lr_set_debug_message (unsigned int message_level, unsigned int on_off);
中文解释:lr_set_debug_message函数设置脚本执行的调试消息级别message_lvl。通过设置消息级别,可以确定发送哪些信息。 启
动设置的方法是将LR_SWITCH_ON作为on_off传递,禁用设置的方法是传递LR_SWITCH_OFF。参数message_level说明:
【日志级别】====【C语言标志】====【值】====【Runtime-setting - Log操作】
【Disabled】====【LR_MSG_CLASS_DISABLE_LOG】====【0】====【不勾选Enable logging】
【Brief】====【LR_MSG_CLASS_BRIEF_LOG】====【1】====【勾选Standard log】
【Extended Log】====【LR_MSG_CLASS_EXTENDED_LOG】====【16】====【勾选Extended log】
【Result Data】====【LR_MSG_CLASS_RESULT_DATA】====【2】====【勾选Data returned by server】
【Parameter Substitution】====【LR_MSG_CLASS_PARAMETERS】====【4】====【勾选Parameter substitution】
【Full Run-Time Trace】====【LR_MSG_CLASS_FULL_TRACE】====【8】====【 勾选 Advanced trace】
【Only on error】====【LR_MSG_CLASS_JIT_LOG_ON_ERROR】====【512】====【勾选send messages only when an error occurs】参数on_off说明:
【LR_SWITCH_ON】启用设置
【LR_SWITCH_OFF】禁用设置
看下面的小例子:
Action()
{
int log_leavl;
log_leavl = lr_get_debug_message();
lr_error_message ("当前是:%d",log_leavl);
return 0;
}
当我设置只有错误信息(error)打印【勾选send messages only when an error occurs】,例子运行结果是:当前是:513;
为什么不是512呢,我发现我实际选择的是【Enable logging + send messages only when an error occurs】,按上面的
参数说明,就是【1+512】,也就是513了;因此:
lr_get_debug_message返回的int数其实是所有勾选操作的代表值相加!
再看下面设置的例子:Action()
{
//设置runtime-setting的日志选项【不勾选Enable logging】
char *a;
a = "ABC";
lr_set_debug_message (LR_MSG_CLASS_EXTENDED_LOG |LR_MSG_CLASS_PARAMETERS,LR_SWITCH_ON);
//打开Runtime-setting Log 的Parameter substitution设置
lr_debug_message(LR_MSG_CLASS_PARAMETERS,"打开参数保存的系统日志");
lr_save_string("aa",a);
lr_debug_message(LR_MSG_CLASS_PARAMETERS,"关闭参数保存的系统日志");
lr_set_debug_message (LR_MSG_CLASS_EXTENDED_LOG |LR_MSG_CLASS_PARAMETERS,LR_SWITCH_OFF);
//关闭Runtime-setting Log 的Parameter substitution设置return 0;
}
因为设置了runtime-setting不打印任何日志,所以正常运行脚本应该没有任何日志输出;
但是使用lr_set_debug_message函数打开了日志的设置(输出保存参数操作的日志)
因此脚本运行到lr_save_string("aa",a)时,就输出了日志如下:打开参数保存的系统日志
Action.c(7): Notify: Saving Parameter "ABC = aa"
关闭参数保存的系统日志==============================================================
参考资料:Loadrunner 8.1 函数手册英文(Virtual User Generator - Help -Function Reference)
希望大家一起努力把lr用熟用透!!!
- 上一篇文章: Loadrunner 用户自定义函数使用
-
如何操作web_reg_save_param获取的参数
2007-11-03
web_reg_save_param可以方便的让你从web页面上获取你需要的一些参数,让你的测试脚本更具有交互性.函数的具体使用请参考帮助文档,这里主要说明一下如何操作它获取的参数.
1.获取单个参数
看下面例子:
web_reg_save_param("param","LB/ic="Value=","RB="","ORD=1",LAST);
上面的语句把页面上发现的第一个值存放到param参数中,当然param和你通常定义的变量是有区别的,它是参数不是变量,这个概念要搞清楚,你不能象下面这样给他赋值:
char testParam[20];
sprintf(testParam,"%s",param);
而应该象下面这样:
sprintf(testParam,"%s",lr_eval_string("{param}"));
下面是一个提交随机内容的函数:
web_submit_form("tpcc.pr.prC_ITEMUpdate.do",
"Snapshot=t7.inf",
ITEMDATA,
"Name=C_ITEM/I_IM_ID", "Value={im_id}", ENDITEM,
"Name=C_ITEM/I_NAME", "Value={i_name2_value}", ENDITEM,
"Name=C_ITEM/I_PRICE", "Value=12.11", ENDITEM,
"Name=C_ITEM/I_DATA", "Value={i_name_value}", ENDITEM,
LAST);
上面大括号中的都是参数,你可以生成一些随机字符串提交,更真实的仿真用户操作.当然你也可以整个把"Value={im_id}"用参数替换,当然你的参数得符合"Value=XXXXX"的格式了:
"Name=C_ITEM/I_IM_ID", "{test_param}", ENDITEM,
也可以整个把它用变量替换:
char test_str[]="Value=afadfafa";
"Name=C_ITEM/I_IM_ID", test_param, ENDITEM,
注意他们之间的差别
2.参数数组
有时候你可能查询回来很多记录,你可能想随机修改其中的某一条,你可以从返回页面获得所有的记录号存放在一个参数数组中:
web_reg_save_param("param_array","LB/ic="Value=","RB="","ORD=ALL",LAST);
其中param_array_1代表参数一,param_array_2代表参数二...,获取数组长度可以这样:
int array_len,rand_id;
char array_name[20];
array_len=atoi(lr_eval_string("{param_array_count}");
随机获取参数:
srand(time(NULL));
rand_id=rand()%array_len+1;
sprintf(array_name,"{param_array_%d}",rand_id);
lr_save_string(lr_eval_string(array_name),"param_rand");
这样,你的随机值就存放到param_rand参数中了.上一篇文章: Loadrunner message函数详细分析
与 web_reg_save_param 相关的文章 -
LoadRunner使用技巧- IP欺骗的使用
2007-11-03
设置IP欺骗的原因
1、 当某个IP的访问过于频繁,或者访问量过大是,服务器会拒绝访问请求,这时候通过IP欺骗可以增加访问频率和访问量,以达到压力测试的效果。
2、 某些服务器配置了负载均衡,使用同一个IP不能测出系统的实际性能。LR中的IP欺骗通过调用不同的IP,可很大程度上的模拟实际使用中多IP访问和并测试服务器均衡处理的能力。
多IP地址的设置
IP地址的设置较为简单,可直接在本地连接中增加IP,或者通过LR自带的工具“IP wizard”设置,当然也可以使用其它软件设置。唯一需要注意的就是注意设置的IP的有效性。
“选项”中的IP设置
使用“选项”对话框中的“常规”选项卡,可以选择IP地址模式。只有在专家模式下操作 Controller 时,才显示该选项卡。
1. 选择“工具”>“选项”。将显示“选项”对话框。选择“常规”选项卡。
需要注意的是,这里的IP地址模式和运行时设置中的常规设置的不同,会导致IP欺骗失效。具体该怎么设置,这里就不讲了,很简单的东西。
启用IP欺骗
从 Controller 启用多个 IP 地址
定义多个 IP 地址后,您就可以设置一个选项,让 Controller 使用该功能。
要从 Controller 启用多个 IP 地址,请执行下列操作:
在 Controller“设计”视图中,选择“场景”>“启用 IP 欺骗器”。
IP欺骗功能验证
IP欺骗已经设置了,但是是不是有效呢?通常会有这样的疑问。下面我们通过一个简单的试验,来验证是否有效。
在脚本的Action()部分增加如下代码:
&nsp; char * ip=lr_get_vuser_ip();
if(ip)
lr_vuser_status_message("The ip address is %s",ip);
else
lr_vuser_status_message("IP spoofing disabled");
然后通过控制器设置并运行场景,在Controller's Vuser 窗口中,大家可以看到如下的结果:
遇到问题总结:
启动IP向导的时候出现:
---------------------------
IP Wizard
---------------------------
The IP wizard does not support DHCP-enabled network cards.Your cards are either DHCP-enabled or configured with invalid settings.
Please contact your system administrator.
Exiting...
是因为不能用动态IP
-
LoadRunner监视的性能计数器
2007-9-10
今天,我先把我整理的一些计数器及其阈值要求等贴出来,这些计数器是针对我对windows操作系统,C/S结构的sql server数据库及WEB平台.net产品测试时的一些计数器;大家可以继续补充,作过unix平台上oracle数据库测试及J2EE架构及WEBLOGIC方面测试的朋友,也希望把自己使用的计数器贴出来,让大家分享。
好了,先说这些了,希望通过这个专题,最终能让大家对自己的测试结果进行分析。
Memory: 内存使用情况可能是系统性能中最重要的因素。如果系统“页交换”频繁,说明内存不足。“页交换”是使用称为“页面”的单位,将固定大小的代码和数据块从 RAM 移动到磁盘的过程,其目的是为了释放内存空间。尽管某些页交换使 Windows 2000 能够使用比实际更多的内存,也是可以接受的,但频繁的页交换将降低系统性能。减少页交换将显著提高系统响应速度。要监视内存不足的状况,请从以下的对象计数器开始:
Available Mbytes:可用物理内存数. 如果Available Mbytes的值很小(4 MB 或更小),则说明计算机上总的内存可能不足,或某程序没有释放内存。
page/sec: 表明由于硬件页面错误而从磁盘取出的页面数,或由于页面错误而写入磁盘以释放工作集空间的页面数。一般如果pages/sec持续高于几百,那么您应该进一步研究页交换活动。有可能需要增加内存,以减少换页的需求(你可以把这个数字乘以4k就得到由此引起的硬盘数据流量)。Pages/sec 的值很大不一定表明内存有问题,而可能是运行使用内存映射文件的程序所致。
page read/sec:页的硬故障,page/sec的子集,为了解析对内存的引用,必须读取页文件的次数。阈值为>5. 越低越好。大数值表示磁盘读而不是缓存读。
由于过多的页交换要使用大量的硬盘空间,因此有可能将导致将页交换内存不足与导致页交换的磁盘瓶径混淆。因此,在研究内存不足不太明显的页交换的原因时,您必须跟踪如下的磁盘使用情况计数器和内存计数器:
Physical Disk\\ % Disk Time
Physical Disk\\ Avg.Disk Queue Length例如,包括 Page Reads/sec 和 % Disk Time 及 Avg.Disk Queue Length。如果页面读取操作速率很低,同时 % Disk Time 和 Avg.Disk Queue Length的值很高,则可能有磁盘瓶径。但是,如果队列长度增加的同时页面读取速率并未降低,则内存不足。
要确定过多的页交换对磁盘活动的影响,请将 Physical Disk\\ Avg.Disk sec/Transfer 和 Memory\\ Pages/sec 计数器的值增大数倍。如果这些计数器的计数结果超过了 0.1,那么页交换将花费百分之十以上的磁盘访问时间。如果长时间发生这种情况,那么您可能需要更多的内存。
Page Faults/sec:每秒软性页面失效的数目(包括有些可以直接在内存中满足而有些需要从硬盘读取)较page/sec只表明数据不能在内存的指定工作集中立即使用。
Cache Bytes:文件系统缓存(File System Cache),默认情况下为50%的可用物理内存。如IIS5.0 运行内存不够时,它会自动整理缓存。需要关注该计数器的趋势变化
如果您怀疑有内存泄露,请监视 Memory\\ Available Bytes 和 Memory\\ Committed Bytes,以观察内存行为,并监视您认为可能在泄露内存的进程的 Process\\Private Bytes、Process\\Working Set 和Process\\Handle Count。如果您怀疑是内核模式进程导致了泄露,则还应该监视 Memory\\Pool Nonpaged Bytes、Memory\\ Pool Nonpaged Allocs 和 Process(process_name)\\ Pool Nonpaged Bytes。
Pages per second :每秒钟检索的页数。该数字应少于每秒一页。
Process:
%Processor Time: 被处理器消耗的处理器时间数量。如果服务器专用于sql server,可接受的最大上限是80-85%
Page Faults/sec:将进程产生的页故障与系统产生的相比较,以判断这个进程对系统页故障产生的影响。
Work set: 处理线程最近使用的内存页,反映了每一个进程使用的内存页的数量。如果服务器有足够的空闲内存,页就会被留在工作集中,当自由内存少于一个特定的阈值时,页就会被清除出工作集。
Inetinfo:Private Bytes:此进程所分配的无法与其它进程共享的当前字节数量。如果系统性能随着时间而降低,则此计数器可以是内存泄漏的最佳指示器。
Processor:监视“处理器”和“系统”对象计数器可以提供关于处理器使用的有价值的信息,帮助您决定是否存在瓶颈。
%Processor Time:如果该值持续超过95%,表明瓶颈是CPU。可以考虑增加一个处理器或换一个更快的处理器。
%User Time:表示耗费CPU的数据库操作,如排序,执行aggregate functions等。如果该值很高,可考虑增加索引,尽量使用简单的表联接,水平分割大表格等方法来降低该值。
%Privileged Time:(CPU内核时间)是在特权模式下处理线程执行代码所花时间的百分比。如果该参数值和"Physical Disk"参数值一直很高,表明I/O有问题。可考虑更换更快的硬盘系统。另外设置Tempdb in RAM,减低"max async IO","max lazy writer IO"等措施都会降低该值。
此外,跟踪计算机的服务器工作队列当前长度的 Server Work Queues\\ Queue Length 计数器会显示出处理器瓶颈。队列长度持续大于 4 则表示可能出现处理器拥塞。此计数器是特定时间的值,而不是一段时间的平均值。
% DPC Time:越低越好。在多处理器系统中,如果这个值大于50%并且Processor:% Processor Time非常高,加入一个网卡可能会提高性能,提供的网络已经不饱和。
Thread
ContextSwitches/sec: (实例化inetinfo 和dllhost 进程) 如果你决定要增加线程字节池的大小,你应该监视这三个计数器(包括上面的一个)。增加线程数可能会增加上下文切换次数,这样性能不会上升反而会下降。如果十个实例的上下文切换值非常高,就应该减小线程字节池的大小。
Physical Disk:
%Disk Time %:指所选磁盘驱动器忙于为读或写入请求提供服务所用的时间的百分比。如果三个计数器都比较大,那么硬盘不是瓶颈。如果只
%Disk Time比较大,另外两个都比较适中,硬盘可能会是瓶颈。在记录该计数器之前,请在Windows 2000 的命令行窗口中运行diskperf -yD。若数值持续超过80%,则可能是内存泄漏。
Avg.Disk Queue Length:指读取和写入请求(为所选磁盘在实例间隔中列队的)的平均数。该值应不超过磁盘数的1.5~2 倍。要提高性能,可增加磁盘。注意:一个Raid Disk实际有多个磁盘。
Average Disk Read/Write Queue Length:指读取(写入)请求(列队)的平均数。
Disk Reads(Writes)/s: 物理磁盘上每秒钟磁盘读、写的次数。两者相加,应小于磁盘设备最大容量。
Average Disksec/Read: 指以秒计算的在此盘上读取数据的所需平均时间。
Average Disk sec/Transfer:指以秒计算的在此盘上写入数据的所需平均时间。
Network Interface:
Bytes Total/sec :为发送和接收字节的速率,包括帧字符在内。判断网络连接速度是否是瓶颈,可以用该计数器的值和目前网络的带宽比较
SQLServer性能计数器:
Access Methods(访问方法) 用于监视访问数据库中的逻辑页的方法。
Full Scans/sec(全表扫描/秒) 每秒不受限的完全扫描数。可以是基本表扫描或全索引扫描。如果这个计数器显示的值比1或2高,应该分析你的查询以确定是否确实需要全表扫描,以及S Q L查询是否可以被优化。
Page splits/sec(页分割/秒)由于数据更新操作引起的每秒页分割的数量。
Buffer Manager(缓冲器管理器):监视 Microsoft® SQL Server? 如何使用: 内存存储数据页、内部数据结构和过程高速缓存;计数器在 SQL Server 从磁盘读取数据库页和将数据库页写入磁盘时监视物理 I/O。 监视 SQL Server 所使用的内存和计数器有助于确定: 是否由于缺少可用物理内存存储高速缓存中经常访问的数据而导致瓶颈存在。如果是这样,SQL Server 必须从磁盘检索数据。 是否可通过添加更多内存或使更多内存可用于数据高速缓存或 SQL Server 内部结构来提高查询性能。
SQL Server 需要从磁盘读取数据的频率。与其它操作相比,例如内存访问,物理 I/O 会耗费大量时间。尽可能减少物理 I/O 可以提高查询性能。
.Page Reads/sec:每秒发出的物理数据库页读取数。这一统计信息显示的是在所有数据库间的物理页读取总数。由于物理 I/O 的开销大,可以通过使用更大的数据高速缓存、智能索引、更高效的查询或者改变数据库设计等方法,使开销减到最小。
.Page Writes/sec (.写的页/秒) 每秒执行的物理数据库写的页数。
.Buffer Cache Hit Ratio. 在“缓冲池”(Buffer Cache/Buffer Pool)中没有被读过的页占整个缓冲池中所有页的比率。可在高速缓存中找到而不需要从磁盘中读取的页的百分比。这一比率是高速缓存命中总数除以自 SQL Server 实例启动后对高速缓存的查找总数。经过很长时间后,这一比率的变化很小。由于从高速缓存中读数据比从磁盘中读数据的开销要小得多,一般希望这一数值高一些。通常,可以通过增加 SQL Server 可用的内存数量来提高高速缓存命中率。计数器值依应用程序而定,但比率最好为90% 或更高。增加内存直到这一数值持续高于90%,表示90% 以上的数据请求可以从数据缓冲区中获得所需数据。
Lazy Writes/sec(惰性写/秒)惰性写进程每秒写的缓冲区的数量。值最好为0。
Cache Manager(高速缓存管理器) 对象提供计数器,用于监视 Microsoft® SQL Server? 如何使用内存存储对象,如存储过程、特殊和准备好的 Transact-SQL 语句以及触发器。
Cache Hit Ratio(高速缓存命中率,所有Cache”的命中率。在SQL Server中,Cache可以包括Log Cache,Buffer Cache以及Procedure Cache,是一个总体的比率。) 高速缓存命中次数和查找次数的比率。对于查看SQL Server高速缓存对于你的系统如何有效,这是一个非常好的计数器。如果这个值很低,持续低于80%,就需要增加更多的内存。
Latches(闩) 用于监视称为闩锁的内部 SQL Server 资源锁。监视闩锁以明确用户活动和资源使用情况,有助于查明性能瓶颈。
Average Latch Wait Ti m e ( m s ) (平均闩等待时间(毫秒)) 一个SQL Server线程必须等待一个闩的平均时间,以毫秒为单位。如果这个值很高,你可能正经历严重的竞争问题。
Latch Waits/sec (闩等待/秒) 在闩上每秒的等待数量。如果这个值很高,表明你正经历对资源的大量竞争。
Locks(锁) 提供有关个别资源类型上的 SQL Server 锁的信息。锁加在 SQL Server 资源上(如在一个事务中进行的行读取或修改),以防止多个事务并发使用资源。例如,如果一个排它 (X) 锁被一个事务加在某一表的某一行上,在这个锁被释放前,其它事务都不可以修改这一行。尽可能少使用锁可提高并发性,从而改善性能。可以同时监视 Locks 对象的多个实例,每个实例代表一个资源类型上的一个锁。
Number of Deadlocks/sec(死锁的数量/秒) 导致死锁的锁请求的数量
Average Wait Time(ms) (平均等待时间(毫秒)) 线程等待某种类型的锁的平均等待时间
Lock Requests/sec(锁请求/秒) 每秒钟某种类型的锁请求的数量。
Memory manager:用于监视总体的服务器内存使用情况,以估计用户活动和资源使用,有助于查明性能瓶颈。监视 SQL Server 实例所使用的内存有助于确定:
是否由于缺少可用物理内存存储高速缓存中经常访问的数据而导致瓶颈存在。如果是这样,SQL Server 必须从磁盘检索数据。
是否可以通过添加更多内存或使更多内存可用于数据高速缓存或 SQL Server 内部结构来提高查询性能。
Lock blocks:服务器上锁定块的数量,锁是在页、行或者表这样的资源上。不希望看到一个增长的值。
Total server memory:sql server服务器当前正在使用的动态内存总量.
监视IIS需要的一些计数器
Internet Information Services Global:
File Cache Hits %、File CacheFlushes、File Cache Hits
File Cache Hits %是全部缓存请求中缓存命中次数所占的比例,反映了IIS 的文件缓存设置的工作情况。对于一个大部分是静态网页组成的网站,该值应该保持在80%左右。而File Cache Hits是文件缓存命中的具体值,File CacheFlushes 是自服务器启动之后文件缓存刷新次数,如果刷新太慢,会浪费内存;如果刷新太快,缓存中的对象会太频繁的丢弃生成,起不到缓存的作用。通过比较File Cache Hits 和File Cache Flushes 可得出缓存命中率对缓存清空率的比率。通过观察它两个的值,可以得到一个适当的刷新值(参考IIS 的设置ObjectTTL 、MemCacheSize 、MaxCacheFileSize)
Web Service:
Bytes Total/sec:显示Web服务器发送和接受的总字节数。低数值表明该IIS正在以较低的速度进行数据传输。
Connection Refused:数值越低越好。高数值表明网络适配器或处理器存在瓶颈。
Not Found Errors:显示由于被请求文件无法找到而无法由服务器满足的请求数(HTTP状态代码404)
-
如何更好的使用LR进行测试
2007-9-04
LR很强大,因为它功能很多,但用起来也会相对比较麻烦,喜欢简单的人都喜欢用WAS进行WEB应用测试,本人使用LR也不是很久,使用它测试过几个项目,每做一次就会有所收获,到现在发现之前自己浪费了不少的时间在弄脚本的时候,总结起来与大家一起分享,对于LR高手来说就是小菜一碟了,新人可以看看
1、不要盲目的开始录制脚本(最好先将要录制的脚本URL弄个表列出来,并加上注释)
2、脚本录制好后不要急于参数化(参数化前将要使用的参数先列出来,适当减少参数个数)
3、取数据时要注意各数据间的关联(不注意关联,会导制取出来的数据与事实不符)
4、需要记录取数据所使用的SQL语句等,并添加注释(以便以后使用,或出现问题时,查找原因)
5、记录应用配置,每次测试前清空以前的LOG记录,测试完成记录本次测试相关数据
6、完成测试后,进行对比分析,得出本系统的最佳配置


