[转]Loadrunner案例:某通信企业Web业务系统的性能测试

上一篇 / 下一篇  2017-10-20 16:24:33 / 个人分类:性能测试

项目背景

该案例是某通信企业Web业务系统的性能测试。该Web业务系统用于管理企业的备品和备件,包括对网络设备的库存管理、库存流转、备品备件的查询统计等功能。其中库存管理、备品备件查询等功能主要是对数据库的增、删、改、查操作,库存流转则主要体现为工作流的实现。

该系统的主要用户是通信企业的备品备件管理人员,通过该系统,管理人员能够对现有的备品备件库数据进行查询、更新,也可以通过该系统提供的业务流程完成备品备件的出库和入库操作。

对系统的测试在系统上线时进行,主要目的是验证系统的性能能否达到用户要求。

性能测试工具Loadrunner

点击下载

项目特点

该项目基于J2EE实现,采用Tomcat作为应用服务器,架构上使用Struts+EJB+Herbinate,在业务上实现了多个流转的流程。

该系统是一个典型的J2EE应用,从性能测试的角度来说,具有很强的代表性。从技术的角度来说,该系统使用了验证码方式防止对系统口令的暴力破解和可能的内部SPAM,由于现在越来越多的系统都采用验证码方式提高系统的安全性,因此在对本案例的描述中也特别给出了针对这种验证码的性能测试解决方案。

该系统的网络环境和设备相对简单,网络环境是企业内部的千兆网络,基本不可能对系统性能造成影响;设备方面,采用一台UNIX服务器作为数据库服务器,一台UNIX服务器作为应用服务器。

该系统是一个以人机交互为主的系统,因此,对系统性能的体现主要通过响应时间来给出。

由于Web应用采用的协议单一(HTTP和HTTPS协议),因此特别适合用商业的性能测试工具(如LoadRunner)来辅助进行测试,本案例的描述中重点结合LoadRunner的使用,描述了在项目性能测试中用LoadRunner等工具进行测试的方法。

性能测试过程

本节描述性能测试的全过程,根据本书第5章的性能测试过程描述,按照PTGM模型分别对性能测试的各阶段进行阐述。

测试前期准备

在了解该项目的基本状况之后,首先开始测试前期准备工作。

1.系统基础功能验证

本案例中描述的性能测试安排在功能验收测试之后,因此在性能测试中不需要额外安排基础功能验证。

2.组建测试团队

根据该项目的具体情况,建立一个5人的团队负责本次测试工作。由于该系统的设备环境和网络环境相对简单,因此没有特别在团队中包括系统工程师,团队的5个成员中,1名是数据库工程师,1名是性能测试设计和分析人员,3名是性能测试开发和实施人员。

在测试开始之前,根据对项目的了解,预计该系统的性能测试难点主要在测试设计和测试脚本实现阶段,由于系统协议单一,架构相对比较简单,且有合适的商业工具可以直接使用,因此在测试工具方面不需要投入太多的精力。

3.测试工具需求确认

考虑到系统测试的要求,确定的测试工具需求如下:

  • 支持HTTP/HTTPS协议层上的测试。
  • 能监控UNIX服务器的主要性能计数器值,如服务器的内存使用状况、CPU使用状况、磁盘I/O情况等。
  • 能监控Windows服务器的主要性能计数器,如服务器的内存使用状况、CPU使用状况、磁盘I/O情况、进程的内存使用情况等。
  • 支持对Oracle数据库的主要性能计数器值进行监控。
  • 支持对Tomcat应用服务器的JVM内存使用状况进行监控。

4.测试工具需求确认

性能预备测试用于对系统建立直观的认识,在正式开始测试之前体验性地使用了本系统的主要功能,根据体验,系统的所有操作均能在4秒之内完成,响应时间相对较长的是登录过程。

测试工具引入

根据测试前期准备确定的测试工具需求,目前市面上的性能测试工具基本都能够支持这些需求,唯一有困难的是“监控Tomcat应用服务器的JVM使用状况”,基本上所有的商业工具都不支持该需求。

最终确定的测试工具包括两个方面的内容:采用LoadRunner工具作为主要的性能测试工具;对Tomcat的JVM使用状况的监控通过自行开发工具来实现。

测试计划

测试计划阶段需要分析用户活动,确定系统的性能目标。

1.性能测试领域分析

根据对项目背景的了解,本性能测试要解决的主要问题为:验证系统是否达到了预期的性能指标。

这些内容对应于第2章中给出的能力验证应用领域。进一步根据第2章的内容,本测试可用的性能测试方法包括PerformanceTesting和StressTesting方法。

2.用户活动剖析与业务建模

本案例描述系统的建模主要通过用户活动建模和业务建模来体现和进行。

根据对被测系统的使用用户进行书面的问卷调查,在问卷基础上进行分析,可以得到如表1所示的典型用户活动分析列表。

表1

注:①“实际使用用户数量”是针对一个具体的业务模块的,此处给出的数据是对某个具体业务模块的估算。本案例中,通信企业实际使用该系统的人数约为1000人,但考虑到选取的“1天”的考察时间范围,每个模块每天的使用者为20~200人不等。

 ②“业务发生数”是根据书面的用户调查方式获取的,具体方法是将用户的平均业务发生数乘以用户数。

表1初步描述了用户对各业务系统的使用情况,可以以此为基础来进一步分析用户场景,并据此设计相应的测试方案和用例,业务场景的分析与企业的实际业务模式相关。

在对用户活动进行建模的过程中,还得到了以下数据:

  1. 平均每天使用该系统的总用户数约为600。
  2. 平均每个用户的loginsession时间为4小时(也就是说,平均每个用户在8小时时间内有4小时处于“使用系统”的状态)。
  3. 平均每个用户在loginsession的时间范围内进行500个业务操作。

根据以上数据,可以用第1章给出的公式进行计算:

并发用户数:600×4/8=300

吞吐量:300×500/(4×60×60)=10,单位是页面浏览数/秒(PageView/sec)。

有了这些数据就可以进行测试场景的设计了。

在分析了用户的行为之后,为了给测试脚本开发提供依据,还需要对每个业务的操作过程进行描述。在本案例中,以“库存流转―审批”为例,对业务操作进行描述。

“库存流转——审批”业务步骤描述如下:

  1. 用户单击“审批”链接,进入审批页面,页面显示所有等待审批的申请单。
  2. 用户选中所有显示审批单中的第一张审批单,单击“审批通过”按钮。
  3. 系统在页面上反馈“审批通过”信息。

从表1中可以看到,该系统的主要业务集中在库存流转流程相关的活动上,因为这些活动都围绕流转进行,在业务场景设计时必须考虑流程之间的交互性。

另外,“导入备件Excel文件”业务的发生频率和实际使用的用户数量都不大,但由于每次的导入操作均会导入大量的数据,导入过程中系统承受的压力很大,因此在设计场景时有必要单独考虑该场景。

3.确定性能目标

本性能测试的应用领域已被确定为能力验证,在确定性能目标时,主要围绕这个方面确定。

本项目是一个开发项目,从需求和设计中可以获得关于该系统性能目标的描述。根据需求和设计文档,该系统的性能约束在文档中的表达如下:

  1. 系统的页面响应时间不超过10秒。
  2. 需要评估导入备件Excel文件对系统性能的影响,如果该操作影响其他业务,需给出建议。
  3. 系统能够稳定运行。

在这些描述中,第(1)条是比较清晰的性能需求描述;第(2)条实际描述的并不是需求,而是希望在性能测试中安排对“导入”操作的性能表现的测试;第(3)条描述的是用户的性能要求,但不够明确。

经过多次沟通,最终确定的明确的性能需求如下:

系统在典型数据量情况下,页面响应时间不超过10秒:典型数据量定义为当前系统的所有备件规模的静态数据和半年的流转数据。

  1. 系统在典型数据量情况下,页面响应时间不超过10秒:典型数据量定义为当前系统的所有备件规模的静态数据和半年的流转数据。
  2. 系统能够在高于实际系统运行压力1倍的压力情况下,持续稳定工作72小时:持续稳定工作定义为在系统运行期间,系统的可用资源不会出现持续性地减少,用户响应速度没有显著变化。

除了这两个直接从文档中反映的系统性能需求,根据和用户、项目经理等的沟通,另外确定的其他性能目标包括:

  1. 评估典型规模的Excel备件文件导入时对系统性能的影响:评估内容包括两个方面,一个方面是对典型规模的Excel文件(考虑到系统实际的备件数据规模,选择一个20MB、包含50000条数据记录的Excel文件)进行导入时的效率评估;另一方面是通过组合场景,判断导入操作对其他操作的影响。
  2. 在页面响应时间要求10秒的情况下,找到系统能够承受的最大用户数量:该要求可以给用户提供一个可扩展性的参考。

表2给出了分析整理后的性能需求描述。

表2

对能力验证应用领域来说,本测试需要重点关注的是业务的响应时间、各服务器的资源使用状况,结合性能测试需求,性能目标可以定义如下:

  1. 在典型用户数量要求的情况下,服务器CPU平均使用率不高于75%,内存使用率不高于75%。
  2. 在稳定性测试的压力情况下,服务器CPU平均使用率不高于95%,内存使用率不高于90%。

4.制定测试时间计划

本案例采用商业性能测试工具LoadRunner进行测试,由于本案例涉及较多的流程交互等内容,因此重点集中在如何设计和实现合理的性能测试脚本,这需要消耗较多的时间和人力资源。

另外,测试结果的分析也需要安排足够的时间进行。本案例的测试时间计划安排如表3所示。

表3

测试设计与开发

测试设计与开发包括测试环境设计、测试场景设计、测试用例设计和测试辅助工具开发多个活动。对本案例而言,测试场景关注用户以何种方式使用本系统,以场景来体现性能测试的目的和目标。

1.测试环境设计

本性能测试需要验证系统在实际生产部署环境上的性能,因此,选择尽可能接近实际生产环境的环境来进行测试。由于本测试的环境就是实际的生产环境,因此在环境设计上,没有太多需要考虑的内容。

最终确定的测试环境如表4所示。

表2给出了用作测试的基础数据量。基础数据量的计算方法在前两个案例中都有描述,在此不再重复。

表4

2.测试场景设计

结合表1的和表2可以很容易地为该案例给出需要的测试场景。

根据上面给出的数据,设定的总并发用户数为300,按照业务模块访问用户数比例给定VU分配比例,为了达到10PageView/sec的吞吐量,每个VU的操作之间间隔应该为300/10=30秒。

根据调查的结果,我们确定了几个典型的测试场景,如表5所示。

表5-1

表5-2

3.测试用例设计

确定测试场景之后,原有的业务操作描述可以更进一步完善为可映射为脚本的测试用例描述。

在本案例中,可以将用户业务操作形成更详细的用例步骤。例如,“审批”业务可以描述如下:

用例编号:TC_XXXX_XX-1

用例条件:用户已登录,登录用于具有审批的权限

用户步骤和验证方法:

  1. 用户单击“库存流转”链接,进入库存流转页面。
    【验证】页面出现“库存流转”提示字符串。
  2. 用户在页面左侧树视图上单击“审批”链接,进入审批页面。
    【验证】页面上出现“申请单列表”提示字符串。
  3. 用户在页面给出的等待审批的申请单列表中选择最上方的一个,单击“审批”按钮,进入审批页面。
    【验证】给出选中审批单信息,页面上出现被选中审批单的编号。
  4. 用户输入审批信息,单击“通过”按钮。
    【验证】页面上出现“审批通过”提示字符串

从该用例的描述可以看到,在每个操作步骤之后,都给出了相应的验证手段。对性能测试来说,验证手段同样关键。性能测试工具(如LoadRunner等)在性能测试过程中为了VU的效率,一般只通过HTTP返回的HTTPCode判断请求是否成功,对于典型的如HTTP500、HTTP404等错误,LoadRunner能够判断,但如果采用了自定义错误页面,或是返回了表示异常状态的页面,LoadRunner便不能发现。

基于以上原因,通常需要在脚本中添加一些用于验证返回页面是否正确的代码,最常用的方法是判断页面中是否存在特定的字符串。因此,在每个用例中都描述了每个步骤结果的验证方法。

4.脚本和辅助工具的开发

本案例采用LoadRunner作为性能测试工具,下面通过该案例首先介绍LoadRunner在性能测试中的一般应用步骤,然后重点说明在性能测试过程中遇到的问题和解决方法,依次演示LoadRunner使用中的一些技巧和技术。

(1)LoadRunner的性能测试过程。

用LoadRunner工具辅助进行性能测试,一般包括录制和调试脚本、设置场景、运行场景、收集结果并分析4个活动。

录制和调试脚本活动使用LoadRunner的VirtualUserGenerator应用(下文中简称为VUGenerator)完成,运行该应用,选择合适的录制协议,打开被测应用的客户端程序(对B/S应用,客户端程序就是浏览器),按照预期即可进行录制。LoadRunner录制的脚本中体现的是客户端和服务器之间的通信数据以及相互的交互关系。

脚本的录制依据事先分析出的用户活动和案例。按照测试用例设计中给出的具体操作描述,打开VUGenerator工具,输入应用的起始URL,根据用例描述执行操作,录制脚本。LoadRunner针对Web应用录制的脚本默认分为vuser_init、Action和vuser_end3段,其中,vuser_init和vuser_end段只在脚本运行时执行一次,而Action段的执行次数由脚本或场景的RuntimeSetting控制。一般来说,在录制脚本时,会把Login和Logout的步骤分别放在vuser_init和vuserend段中,而把针对业务的操作步骤放在Action段中。

VUGenerator同时提供了对脚本调试的良好支持。脚本录制完成后,需要经过一个仔细的调试阶段才能保证脚本确实准确无误地反映了计划中的测试意图。调试过程中经常进行的操作是参数化、关联和调试输出。

设置场景活动由LoadRunner的Controller工具支持。运行Controller工具,根据测试设计中确定的典型测试场景(见表1),将不同的脚本按照场景中设计的比例分配到一个场景中。并且,测试场景中还需要根据设计的典型场景中的“性能计数器”项目,设置需要进行监控的性能计数器内容。图1描述的是根据表5设计的“系统应用典型场景1”实施的场景。

图1

场景设置涉及的细节内容较多,除了在该场景中分配执行各脚本的VU数量外,还需要根据测试设计添加需要增加的性能计数器(见图2),最后,特别需要关注的是针对脚本的RuntimeSetting设置(见图3),例如,表5给出的“典型场景1”中描述了需要每个脚本Action部分迭代100次,这就需要在Controller的设置中给出每个脚本的迭代次数设置。

图2

图3

运行场景活动相对简单,单击Run页面中的StartScenario按钮,Controller就会自动开始运行场景,并在ScenarioStatus中显示运行时的信息。

收集结果并分析活动需要Analysis应用的支持,Analysis应用可以被独立启动,也可以从Controller程序中调用。从Controller程序中调用时,Analysis应用直接读取本Controller当前场景运行时的信息。图4给出**alysis应用运行时的界面。

图4

Analysis应用能够根据用户设定的性能计数器生成各种性能报表。不过,Analysis最多也只能起到辅助进行性能测试分析的作用,要对性能测试的结果进行分析,还要依靠测试分析者的经验、技能和对系统的了解。

(2)录制“登录”脚本。

针对该应用录制登录脚本时,验证码是一个首要的困难。

验证码是在进行登录或内容提交时,页面上随机出现的人工可识别但机器不可识别的验证字符串(一般是采用背景、扭曲等方式产生的图片),要求登录或提交内容的同时输入,如果验证码输入错误,则不允许进行要求的操作。

本案例中的被测系统使用了验证码技术,其要求输入验证码的页面内容如图5所示。

验证码可以有效防止采用机器猜测方法对口令的刺探,目前己经被许多Internet或Intranet应用接受为标准的实现方式。但对性能测试来说,验证码却带来了很大的问题。因为验证码具有阻止通过自动工具尝试的特性,因此,对于本质上也是自动化工具的性能测试工具,验证码同样具有相当的威力。

图5

具体到本案例系统,在录制脚本时,LoadRunner可以录制用户输入的“用户名”、“密码”和“验证码”信息,但在回放时,由于要求的验证码与录制时的验证码不可能相同,因此回放必然会失败。

为使性能测试能够顺利进行,需要采用某种方法解决上述问题。在笔者的实际工作中,通常使用下面3种方法解决该问题。

第1种方法是最容易想到的方法——在被测系统中暂时屏蔽验证功能,也就是说,为性能测试临时修改应用,在应用中屏蔽验证码(也就是说,无论用户输入的是什么验证码,应用都认为其是正确的)。

这种方法最容易实现,对性能测试结果也不会有太大的影响。这种方式去掉了“验证验证码正确性”这个环节,从理论上来说,测试得到的结果与存在“验证验证码正确性”环节的应用系统存在细微的差异,不过考虑到此环节一般不会成为系统性能瓶颈,因此认为这种处理方式对性能测试结果没有太大的影响。

这种方法对于处于未上线状态或在受控的测试环境中运行的系统非常适用,但对于已经实际上线运行的系统来说,这种方法有一个明显的问题:屏蔽验证功能会对己经在线运行的业务造成非常大的安全性风险。

因此,我们建议在受控的测试环境中采用该方法,但对于已上线的系统来说,不推荐使用该方法。

第2种方法是在第1种方法的基础上稍微进行一些改进。

第1种方法的主要问题是安全性问题,为了应对对在线系统安全性的威胁但在其中留一个“后门”——设定一个“万,可以在修改程序时不取消验证,能验证码”,只要用户输入该“万能验证码”,应用就认为验证通过,否则,还是按照原先的验证方式进行验证。

这种方式仍然存在安全性问题,但由于可以通过管理手段将“万能验证码”控制在一个较小的范围内,而且只在性能测试期间保留这个“后门,基本上可以看作是可靠的。

相对第1种方法来说,这种方法在安全性方面进行了改进,在能够通过管理手段控制“万能验证码”范围的情况下,该方法不失为一种简单易行且相对安全的方法。

第3种方法采用更进一步的方法来处理验证码的问题。

LoadRunner能够调用外部的DLL或组件接口,考虑到这个特性可以根据“验证码验证”的实现,写一个获取验证码的动态库,在测试脚本中调用其接口即可。关于如何在LoadRunner中使用外部DLL,参见本书第11章的内容。

在使用以上验证码处理的方法时,特别要注意,如果针对的是己上线运行的实际系统,无论用哪种方法,测试完成后,都必须立刻将应用恢复,并对系统进行一次安全审计,以免在测试期间被他人入侵。

在本案例中,采用第2种方法来解决验证码带来的问题。

以下是脚本中与登录相关的部分代码:

图6-1

图6-2

这段脚本中灰色背景的粗斜体内容就是修改系统实现后留下的“后门”,其中,5847是在代码中控制的一个“万能验证码”,主要用户输入该验证码,系统就认为验证通过。

细心的读者还会发现,这段代码已经经过了关联处理,其中粗斜体标识的内容就是关联产生的参数内容。这段代码的关联是通过LoadRunner的“自动关联”方式实现的,具体实现方法请见第11章。

解决了验证码和登录时关联的问题后,登录脚本还需要处理的另一个问题就是针对输入的用户名和口令进行参数化处理,本案例中共使用了10组不同的用户名和口令组合。对用户名和口令实现参数化的具体步骤请见第11章。

(3)录制“新建申请单”脚本。

录制“新建申请单”脚本需要首先按照设计中该用例的操作步骤进行录制,以下是按照“新建申请单”用例步骤进行录制后生成的部分脚本代码。

图7

从脚本中可以看到,脚本中给出了申请的发起时间和到期时间,为了使脚本具有更好的适应性,我们决定将这两个时间分别以“当前时间”和“当前时间的前4天”进行替代,这需要对脚本进行参数化操作。在VUGenerator中,选中需要参数化的内容(两个时间),从右键菜单中选择Replacewithaparameter命令,在出现的对话框中设定参数类型为Date/Time,设置时间格式为适合的格式,如图8所示。

设置到期时间时,需要将参数在当前时间的基础上再增加4天。图9所示为设置到期时间的对话框,要注意其中设置的Offsetparameterby选项。

另外,为了便于直观地识别数据是在哪次操作时插入的,在新建申请单时将“备注”的内容修改为“test-”+“当前时间”(当前时间精确到秒)。

图8

图9

参数化修改完成后的脚本代码如下:

图10

除了参数化之外,在脚本中还需要体现“验证返回结果是否正确”,验证返回结果是否正确通过LoadRunner提供的web_eg_find函数实现。该函数的原型是:

图11

在脚本中加入该函数可以根据页面是否存在指定的文本等来验证系统处理的正确性。在用例设计时我们给出了“审批”业务的用例,其中包括的每个“验证”点都可以用这种方式来处理。例如,对给出的“【验证】页面上出现‘申请单:列表’提示字符串”要求,可以在指定的发送请求的语句后添加下面的语句来验证:

Web_reg_find("Text=申请表:列表",LAST);

该语句可以验证返回的页面上是否包含“申请表:列表”文本内容。

(4)录制“审批”脚本。

“审批”涉及到“流程”的概念,测试场景中要求一部分用户“新建”申请单,另一部分用户对已有的申请单进行“审批”操作。录制脚本时,假设录制了对某一条己有的申请单的“审批”,在回放时,如果指定的申请单已经被处理,则脚本的处理就会出错。

图12给出了审批时能看到的待审批申请单列表,在性能测试过程中,每个VU看到的列表都会有所不同,为了使性能测试时每个VU都能够顺利执行(处理待审批的申请单),必须在脚本中约定申请单的处理规则。为简单起见,我们约定的规则是“每个VU都只处理当前未被处理申请单列表中的第一条记录”。

图12

为了实现这个规则,必须对录制后的脚本进行一些处理。未处理的录制生成脚本的相关部分代码如下:

图13

/*动作2——单击指定的审批单记录,给出审批单的详细信息,允许用户对其进行审批*/

图14

/*动作3——填写审批单后进行提交,提交为"通过审批"*/

图15

以上代码中的数字“20051223004”表明了要处理的记录的ID。动作2和动作3都使用了唯一标识审批单记录的ID(数字20051223004)来对指定的审批单操作,那么,这个审批单的ID是从哪里得到的呢?

注意动作1,该动作返回当前所有可被处理的审批单列表,几乎可以肯定,用于标识审批单ID的数字是作为该动作的响应返回给我们的。在VUGenerator中切换到TreeView视图(单击工具栏中的ViewTree按钮),选择ServerResponse选项卡,可以看到图16所示的结果。

将图16显示的信息与图15进行对比,图15是浏览器呈现的页面,而图16给出的则是该页面的对象信息和以文本方式显示的HTML内容。

图16左侧树型的3个radio:appids节点对应于图15显示的3条待处理审批单。而且,从右侧显示的HTML文本内容来看,这个Radio的value就是在后续脚本中需要使用到的用作ID的数值。

TAG:

 

评分:0

我来说两句

日历

« 2021-12-02  
   1234
567891011
12131415161718
19202122232425
262728293031 

我的存档

数据统计

  • 访问量: 1139
  • 日志数: 5
  • 建立时间: 2017-10-20
  • 更新时间: 2017-10-20

RSS订阅

Open Toolbar