发明内容
本申请提供一种web service压力测试方法,以解决现有的压测工具采用基于SOAP报文的方式进行压力测试导致学习成本高、操作繁琐的问题。本申请另外提供一种web service压力测试装置。
本申请提供一种web service压力测试方法,包括:
获取被测web service的配置信息、以及按照预先设定的方式执行web service服务调用的测试代码;
在预处理阶段,修改并编译所述测试代码,得到可执行的测试代码;所述修改是指将所述测试代码修改为:根据入口参数提供的客户端以及方法对象执行web service服务调用,其中,所述客户端封装了支持web service服务调用的协议;
在测试执行阶段,每个测试线程使用对应于被测web service的客户端和方法对象作为入口参数,调用所述可执行的测试代码完成测试任务。
可选的,所述被测web service的配置信息包括:被测服务名称、被测方法名称、以及被测web service的URL信息。
可选的,在所述预处理阶段,还执行下述操作:
根据所述被测web service的配置信息,初始化所述对应于被测web service的客户端和方法对象;
相应的,所述每个测试线程使用对应于被测web service的客户端和方法对象作为入口参数是指,每个测试线程使用上述在预处理阶段已初始化的客户端和方法对象作为入口参数。
可选的,所述方法以JMeter插件的形式实现;
相应的,所述被测web service的配置信息以及所述测试代码是通过JMeter的图形用户界面获取的;
所述预处理阶段是指,JMeter中的前置处理阶段。
可选的,在所述前置处理阶段修改所述测试代码还包括:
在所述测试代码的入口参数中添加测试所需的自定义参数;
用所述自定义参数替换所述测试代码中的相应参数化变量;
相应的,在测试执行阶段,每个测试线程在调用所述可执行的测试代码完成测试任务之前,执行下述操作:
通过比对从所述图形用户界面获取的测试代码和由CSV组件进行参数替换后的测试代码,获取参数化变量被替换后的具体值;
相应的,在测试执行阶段,每个测试线程调用所述可执行的测试代码完成测试任务时,所使用的入口参数还包括:所述参数化变量被替换后的具体值。
可选的,所述根据入口参数提供的客户端以及方法对象完成web service服务调用是指,根据入口参数提供的客户端以及方法对象,通过反射方式完成web service服务调用。
可选的,在前置处理阶段修改并编译所述测试代码之前,执行下述操作:
将所述测试代码所使用的第三方jar包加载到对应的类加载器中。
可选的,在所述前置处理阶段修改所述测试代码还包括:
修改所述测试代码的返回语句,使其返回信息包括:执行web service服务调用的入口参数信息、以及结果信息。
可选的,在测试执行阶段,每个测试线程调用所述可执行的测试代码后,执行下述操作:
将所述调用操作返回的入口参数信息和结果信息,分别添加到JMeter结果树的request属性及response属性中。
可选的,在前置处理阶段修改并编译所述测试代码后,执行下述操作:
将编译后生成的.class文件显示的加载至对应的类加载器中;
根据显示加载返回的类,通过反射机制初始化可执行对象;
相应的,所述在测试执行阶段,每个测试线程调用所述可执行的测试代码 完成测试任务是指,每个测试线程调用所述已初始化的可执行对象,完成测试任务。
相应的,本申请还提供一种web service压力测试装置,包括:
信息与代码获取单元,用于获取被测web service的配置信息、以及按照预先设定的方式执行web service服务调用的测试代码;
测试预处理单元,用于在预处理阶段,修改并编译所述测试代码,得到可执行的测试代码;所述修改是指将所述测试代码修改为:根据入口参数提供的客户端以及方法对象执行web service服务调用,其中,所述客户端封装了支持web service服务调用的协议;
测试执行单元,用于在测试执行阶段,每个测试线程使用对应于被测web service的客户端和方法对象作为入口参数,调用所述可执行的测试代码完成测试任务。
可选的,所述信息与代码获取单元获取的被测web service的配置信息包括:被测服务名称、被测方法名称、以及被测web service的URL信息。
可选的,所述测试预处理单元包括:
代码修改子单元,用于修改所述测试代码,所述修改是指将所述测试代码修改为:根据入口参数提供的客户端以及方法对象执行web service服务调用;
代码编译子单元,用于编译修改后的测试代码,得到可执行的测试代码;
所述测试预处理单元还包括:
客户端初始化子单元,用于根据所述被测web service的配置信息,初始化所述对应于被测web service的客户端和方法对象;
相应的,所述测试执行单元具体用于,每个测试线程使用所述客户端初始化子单元初始化的客户端和方法对象作为入口参数,调用所述可执行的测试代码完成测试任务。
可选的,所述装置以JMeter插件的形式实现;
相应的,所述信息与代码获取单元具体用于,通过JMeter的图形用户界面获取所述被测web service的配置信息以及所述测试代码。
可选的,所述代码修改子单元除了包括:
服务调用修改子单元,用于将所述测试代码修改为:根据入口参数提供的 客户端以及方法对象执行web service服务调用;
所述代码修改子单元还包括:
自定义参数修改子单元,用于在所述测试代码的入口参数中添加测试所需的自定义参数;
参数化变量替换子单元,用于用所述自定义参数替换所述测试代码中的相应参数化变量;
相应的,所述测试执行单元除了包括:
服务调用子单元,用于每个测试线程使用对应于被测web service的客户端和方法对象作为入口参数,调用所述可执行的测试代码完成测试任务;
所述测试执行单元还包括:
参数值获取子单元,用于在触发所述服务调用子单元之前,每个测试线程通过比对从所述图形用户界面获取的测试代码和由CSV组件进行参数替换后的测试代码,获取参数化变量被替换后的具体值;
相应的,所述测试执行单元所使用的入口参数还包括,所述参数值获取子单元获取的参数化变量被替换后的具体值。
可选的,所述测试执行单元是通过反射方式完成web service服务调用的。
可选的,所述测试预处理单元还包括:
jar包加载子单元,用于在触发所述代码修改子单元之前,将所述测试代码所使用的第三方jar包加载到对应的类加载器中。
可选的,所述代码修改子单元还包括:
返回语句修改子单元,用于修改所述测试代码的返回语句,使其返回信息包括:执行web service服务调用的入口参数信息、以及结果信息。
可选的,所述测试执行单元还包括:
返回信息处理子单元,用于将所述调用操作返回的入口参数信息和结果信息,分别添加到JMeter结果树的request属性及response属性中。
可选的,所述测试预处理单元还包括:
类加载子单元,用于将所述代码编译子单元生成的.class文件显示的加载至对应的类加载器中;
可执行对象初始化子单元,用于根据所述类加载子单元执行加载操作返回 的类,通过反射机制初始化可执行对象;
相应的,所述测试执行单元具体用于,每个测试线程调用所述已初始化的可执行对象,完成测试任务。
与现有技术相比,本申请具有以下优点:
本申请提供的web service压力测试方法,首先获取被测web service的配置信息以及测试代码,然后在预处理阶段将所述测试代码修改为根据入口参数提供的客户端以及方法对象执行web service服务调用,并采用动态编译的方式得到可执行代码,在测试执行阶段,每个测试线程使用对应于被测web service的客户端和方法对象作为入口参数,调用所述可执行的测试代码完成测试任务。本技术方案由于内置了支持web service服务调用相关协议的客户端,因此提供测试代码的测试人员无需了解网络协议报文的细节,也不用在协议报文层面进行编码,而是可以采用其熟悉的编程语言、直接按照预先设定的方式进行web service服务调用即可,从而不仅降低了测试人员的学习成本,而且简化了编写测试代码的工作量,同时也为测试过程的参数化提供了一种简便途径。
具体实施方式
在下面的描述中阐述了很多具体细节以便于充分理解本申请。但是本申请能够以很多不同于在此描述的其它方式来实施,本领域技术人员可以在不违背 本申请内涵的情况下做类似推广,因此本申请不受下面公开的具体实施的限制。
在本申请中,分别提供了一种web service压力测试方法,以及一种web service压力测试装置,在下面的实施例中逐一进行详细说明。为了便于理解,先对本技术方案和实施例作简要说明。
本技术方案提供的一种web service压力测试方法,通过将测试代码修改为根据入口参数提供的客户端和方法对象执行web service服务调用,并在测试阶段调用编译后的可执行测试代码,从而完成压力测试。采用本技术方案,由于内置了支持web service服务调用协议的客户端,测试人员只需在测试代码(也称测试脚本)中直接调用被测web serivce提供的服务接口,而不用在协议报文层面进行编码,从而可以有效减少测试人员对网络协议的学习成本,简化测试代码的编写工作,提高压力测试的整体效率。
其中,所述客户端封装的支持web service服务调用的协议包括:简单对象访问协议SOAP(Simple Object Access Protocol)。SOAP是一种用于在应用程序之间进行交互的通信协议,是web service三要素之一,其通过XML来实现消息描述、并通过HTTP等传输协议实现消息传输。当然,在具体实施中,本技术方案内置的客户端还可以封装与web service服务调用相关的其他标准协议,只要所述客户端能够满足测试人员的压测需求,就同样可以简化测试人员的学习成本,减少编码的工作量。
在实施本技术方案时,可以自行编写封装了上述web service协议的客户端,也可以采用现有技术中已有的客户端,从而简化实施过程。考虑到XFire是新一代Web Service框架,不仅提供了简单的API以支持Web Service体系中的各项标准协议和许多新的规范,并且提供多种客户端调用方式。因此,本文描述的实施例提供了一种优选实施方式,即采用XFire客户端作为内置客户端实现本申请提供的技术方案。
在具体实施时,本申请提供的方法可以作为一个完整的技术方案独立实现,也可以从简化实施过程的角度出发,将上述方法作为已有测试工具的插件来实现。考虑到JMeter是目前测试人员通常使用的压测工具之一,因此本实施例采用JMeter插件的形式实现本技术方案。其他测试工具如果可以像JMeter一样提供开源的接口API调用,也可以在其他测试工具的基础上、同样采用动态编译的思路实现本技术方案。
此外需要说明的是,本技术方案对于测试人员提供的测试代码是采用何种计算机语言编写的,并不做具体限定。在本实施例中,考虑到各种开发语言的应用普及程度,所述测试代码是采用Java语言编写的,并且利用了Java的反射机制实现web service服务调用。在其他实施方式中,在具备相应编译工具的条件下,测试人员也可以提供用其他计算机语言编写的测试代码,例如同样支持反射机制的objective-C,或者其他计算机语言,只要能够支持根据入口参数传入的客户端和方法对象完成web service服务调用就同样可以实现本技术方案。
下面对本实施例进行详细描述。请参考图2,其为本申请的一种web service压力测试方法的实施例的流程图。所述方法包括如下步骤:
步骤201:获取被测web service的配置信息、以及按照预先设定的方式执行web service服务调用的测试代码。
在具体实施时,可以通过向测试人员展示图形用户界面,提示测试人员输入被测web service的配置信息以及所述测试代码(也称测试脚本),也可以从测试人员提供的数据文件中读取上述信息,从而完成本步骤的操作。
由于本实施例是以JMeter插件的形式实现的,因此在本步骤中可以从所述JMeter插件的取样器(sampler)配置界面获取被测web service的配置信息以及测试代码。为了便于理解,先对采用JMeter插件进行压力测试作简要说明。
通过JMeter插件进行web service压力测试,其基本原理是通过线程组模拟并发用户对web service的访问。首先,通过取样器的配置界面获取测试人员提供的被测web service的配置信息以及测试代码等信息,随后在初始化线程组执行测试时,每个线程通过取样器调用测试代码,执行向服务器发送请求并记录服务器响应信息的操作,从而完成一次测试。此外,在执行测试之前,可以通过前置处理器(Per Processors)进行相关的准备工作,在测试任务完成后,可以通过后置处理器(Post Processors)进行必要的测试收尾工作。
本步骤通过所述JMeter插件的配置界面获取的被测web service的配置信息包括:被测服务名称、被测方法名称、以及被测web service的URL信息。请参见图3,其为本实施例提供的JMeter插件的配置界面的示意图,测试人员可以在“WS服务配置”区域中提供被测web service的配置信息,其中,ws_url对应文本框为被测web service的URL信息,serviceName对应文本框为被测服务名称,methodName对应文本框为被测方法名称,java code对应文本框为用户 提供的测试代码。从该图形用户界面中还可以获取测试人员设置的访问服务器的超时时间timeout。
由于本技术方案内置了客户端,该客户端封装了支持web service服务调用的相关协议,因此测试人员不用在协议报文层面进行编码,可以按照预先设定的方式执行web service的服务调用,由本技术方案在后续步骤202中自动执行这部分代码的修改和编译操作。在本实施例的一个具体例子中,测试人员提供的用Java编写的测试代码片段如下所示:
在上述例子提供的测试代码片段中,测试人员按照预先设定的方式,直接采用被测服务名称中的类名(未包含路径部分)和被测方法名称,完成了web service服务调用部分的代码,即:credibleService.isCredible(),在后续步骤202中会对这部分代码进行相应的修改替换。在其他实施方式中,也可以预先设定其他的服务调用方式,只要测试人员按照该方式编写服务调用代码,本技术方案在步骤202中对采用该方式的服务调用代码进行修改替换,就同样可以实现本技术方案。
步骤202:在预处理阶段,修改并编译所述测试代码,得到可执行的测试代码;所述修改是指将所述测试代码修改为:根据入口参数提供的客户端以及方法对象完成web service服务调用。
本步骤为执行压力测试之前的预处理阶段,主要完成修改并编译测试代码的工作。由于本实施例是以JMeter插件的形式实现的,本步骤所述的预处理是指,在测试执行之前通过前置处理器完成相关的准备工作,因此本阶段也称为前置处理阶段。在本阶段执行如下所述的步骤202-1至步骤202-5,下面结合附图4作进一步的详细说明。
步骤202-1:将所述测试代码所使用的第三方jar包加载到对应的类加载器中。
由于测试人员提供的java测试代码,可能需要引入第三方jar包,这些jar包文件通常位于对应的testplan文件夹下。在压力测试执行之前,可以将所有用到的第三方jar都提前加载到对应的类加载器(classloader)中。
在Java运行过程中动态加载jar包,通常可以使用java.net.URLClassLoader类加载器,该加载器可以通过指定路径将对应的jar包或者class文件加载到类空间。具体实施时,可以通过遍历存放第三方jar包的目录,获取所有需加载的第三方jar包文件,然后通过URLClassLoader类提供的addURL()方法完成动态加载。
步骤202-2:根据所述被测web service的配置信息,初始化所述对应于被测web service的客户端和方法对象。
作为一种可行的实施方式,每个测试线程可以自己初始化对应于被测web service的客户端(简称web service客户端)和方法对象,然后使用所述客户端和方法对象作为入口参数、调用可执行的测试代码完成测试任务。
为了提高执行效率,本实施例提供一种在前置处理阶段初始化web service客户端和方法对象的优选实施方式,采用这种方式,在启动多线程进行压力测试时,每个线程就可以使用统一的静态客户端和静态方法对象,从而有效避免每个线程都执行同样的初始化操作可能导致的性能瓶颈。
在步骤201中获取了被测web service的配置信息,包括:被测服务名称serviceName,被测方法名称methodName和被测web service的URL信息wsUrl,本步骤使用上述信息初始化所述客户端和方法对象。下面给出了初始化XFire客户端的Java示例代码:
Class<?>className=Class.forName(serviceName);
Service service=new ObjectServiceFactory().create(className);
XFireProxyFactory factory=new XFireProxyFactory(XFireFactory
.newInstance().getXFire());
Object wsService=factory.create(service,wsUrl);
通过上述代码片段完成了XFire客户端的初始化,还可以进一步按照如下Java示例代码进行客户端的超时设置,其中超时时间的具体值timeout可以从JMeter图形用户界面获取:
Client client=Client.getInstance(wsService);
client.setProperty(CommonsHttpMessageSender.HTTP_TIMEOUT,timeout);
完成所述客户端的初始化后,可以进一步通过Java的反射机制,根据被测方法名称methodName,从所述客户端中获取对应的方法对象method。从而在后续步骤203执行测试时,每个线程就可以使用已初始化好的客户端wsService和方法对象method作为入口参数,调用可执行的测试代码完成测试任务。
步骤202-3:修改所述测试代码,生成待编译的java文件。
本步骤将已获取的Java测试代码修改为:根据入口参数完成服务调用,并生成对应的Java文件。此外,本步骤进行的代码修改还可以包括:对参数化变量的处理、对返回语句的替换、以及添加相应的引用语句。该处理过程包括如下所示的步骤202-3-1至步骤202-3-4,下面结合附图5逐一进行说明。
步骤202-3-1:增加import语句。
针对后续需要做的代码修改,增加import引用语句。例如,后续进行测试代码的修改时需要用到JDK提供的List和ArrayList数据结构、以及XFire客户端,那么在测试代码的开始部分可以添加如下所示的import引入语句:
import org.codehaus.xfire.service.service;
import java.util.ArrayList;
import java.util.List;
步骤202-3-2:替换服务调用语句。
由于本技术方案内置了web service客户端,因此测试人员不需要在协议层面进行编码,也不需要自己初始化客户端,这些对于测试人员来说都是透明的,测试人员只需要在测试代码中按照预先设定的方式直接进行服务调用即可。本步骤则在测试代码中增加入口参数:客户端和方法对象,并将原来的服务调用语句替换为根据入口参数执行服务调用,由于本实施例中的测试代码是采用Java语言编写的,因此服务调用部分的代码采用了反射写法。
仍以步骤201中提供的测试代码片段为例,在该例子中,测试代码按照预先设定的方式直接采用被测服务名称的类名(未包含路径部分)和被测方法名称,进行web service服务调用,调用语句如下所示:
boolean ret=credibleService.isCredible(query);
本步骤主要进行两方面的代码修改,首先,通过正则匹配的方式定位测试 代码中的runTest()语句行,并在括号中添加两个入口参数:method和service,其中service是用于进行服务调用的客户端参数,method是用于进行服务调用的方法对象参数;然后,从已获取的被测服务名称serviceName中提取类名部分,利用所述类名和方法名称,采用正则匹配的方式在测试代码中定位符合预定方式的服务调用语句,并将该语句替换为使用入口参数进行服务调用的反射写法。此外,为了在后续的步骤202-3-4中能够将入口参数和服务调用结果都以对象的形式返回,可以将服务调用返回结果的类型替换为Object。
经过修改,上述测试代码片段中的runTest()语句行被替换为如下语句:
public Object runTest(Method method,Object service){
上述测试代码片段中的服务调用语句被替换为如下形式:
Object ret=method.invoke(service,query);
步骤202-3-3:进行参数化变量的处理。
作为一种优选实施方式,本实施例还实现了测试过程的参数化。
现有压力测试基本上都是基于协议报文的(例如SOAP报文),通过截获并回访SOAP报文的方式进行压力测试。采用这种方式,如果要实现测试过程的参数化,通常需要对协议报文逐一解析,明确获悉参数会以何种形式被封装在协议报文中,对于可以支持多种协议格式的web service来说,要通过上述方式在SOAP报文中实现参数化,通常难度很大。而本技术方案由于内置了客户端,并且采用动态修改、编译测试代码的方式,因此为测试过程的参数化提供了便利。
由于本实施例以JMeter插件的形式实施,而JMeter自带配置元件用于提供对静态数据配置的支持,其中的CSV Data Set config组件(以下简称CSV组件)可以从本地数据文件中以行为单位读入数据配置信息,然后根据预先指定的分隔符(例如逗号)分隔成若干个参数值,并用这些参数值替换测试代码中的参数化变量部分,然后传递给某个线程。采用这种方式,每个线程都可以使用不同的参数值进行web service服务调用,使得压力测试过程更为灵活。
使用CSV组件的上述功能,测试人员在编写测试代码时,可以将需要参数化的部分写为CSV组件可识别的参数化变量的形式,例如,${userid}。
本实施例为了实现测试过程的参数化,将自定义参数以runTest()方法入口参数的形式传入,并在每个线程开始执行测试之前,获取被CSV组件替换的具体 参数值、并用这些具体参数值作为入口参数调用可执行的测试代码(这部分请参见步骤203中的相关说明)。
具体到本步骤中,主要进行两方面的代码修改,首先通过正则匹配的方式定位测试代码中的runTest()语句行,并在括号中添加所需的自定义参数,在具体实施中,这部分处理可以与步骤202-3-2在入口参数中添加客户端参数和方法对象参数的操作步骤合并处理;然后,根据参数化变量的形式${},通过正则匹配的方式定位测试代码中的使用参数化变量的赋值语句,并用所述自定义参数替换赋值语句中的相应参数化变量。
仍以步骤201中提供的测试代码片段为例,在所述代码片段中有两个参数化变量${userid}和${ip},经过上一步骤202-3-2和本步骤的修改,所述测试代码片段中的runTest()语句行被替换为如下语句:
public Object runTest(Method method,Object service,String useridStr,String ipStr){
所述代码片段中的两行赋值语句被替换为如下形式:
String userid=useridStr;
String ip=ipStr;
步骤202-3-4:修改返回语句。
为了便于在测试完成之后进行问题定位与排查,本实施例还提供一种优选实施方式:通过对测试代码中的return语句的替换修改,使得测试代码中的runTest()方法既可以返回执行web service服务调用所采用的入口参数信息,也可以返回服务调用的结果信息。
具体说,本步骤可以通过正则匹配的方式定位测试代码中的return语句,然后可以将该语句替换为实现如下功能的语句:在新定义的对象列表中依次添加各个入口参数,并在所述对象列表中添加服务调用的返回结果,最后将所述对象列表作为runTest()方法的执行结果返回。
至此,通过上述步骤202-3-1至步骤202-3-4,完成了对测试代码的修改。在具体实施时,可以将修改后的测试代码保存为.java文件,例如wsTest1.java,为后续步骤202-4进行动态编译做好准备。
202-4:采用JDK提供的系统编译器JavaCompiler编译修改后的测试代码。
本步骤编译步骤202-3修改后生成的.java文件,从而得到可执行的测试代码。
在本实施例的一个具体例子中,采用JDK自带的Java编译器JavaCompiler完成本步骤的编译操作。由于测试代码中可能需要引入第三方jar包,在上述步骤201中执行了相应的动态加载操作,在本步骤中为了避免编译过程中出现错误,可以将步骤201中涉及的jar包所在目录,添加到环境变量classpath中,并在编译参数设置中通过“-cp”指定环境变量classpath。执行本步骤的编译操作后,将生成对应的.class文件。
202-5:初始化可执行对象。
在步骤202-4中编译测试代码后,得到了可执行的测试代码。作为一种可行的实施方式,可以在后续步骤203中由每个测试线程使用当前线程的类加载器将编译生成的类加载至JVM,并通过反射机制实例化可执行对象(包括:脚本对象实例和脚本方法对象),然后再通过调用可执行对象完成本次测试任务。
为了提高执行效率,本实施例提供一种在前置处理阶段初始化可执行对象的优选实施方式,即,在前置处理阶段完成步骤202-4的编译操作后,直接将生成的.class文件显示地加载到当前的类加载器中,并实例化可执行对象。采用这种方式,在启动多线程进行压力测试时,每个线程就可以使用上述已初始化的统一的静态可执行对象,从而有效避免每个线程都执行重复的加载和实例化操作可能导致的性能瓶颈。
在具体实施时,可以采用URLClassLoader类提供的loadClass()方法,将编译后生成的.class文件显示地加载到类加载器中,然后根据加载操作返回的类,通过newInstnce()方法获取可执行脚本对象的实例,然后再根据方法名"runTest"通过反射机制查询得到具体的脚本方法对象。
步骤203:在测试执行阶段,每个测试线程使用对应于被测web service的客户端和方法对象作为入口参数,调用所述可执行的测试代码完成测试任务。
在测试执行阶段,可以并发初始化多个测试线程,在每个测试线程中调用步骤202编译生成的可执行测试代码,从而完成测试任务。由于本实施例以JMeter插件的形式实施,因此测试人员可以在关于线程组的配置界面上设置并发线程数目等信息,初始化相应数量测试线程的操作由JMeter自动完成。
其中,每个线程执行的操作包括如下所示的步骤203-1至步骤203-3,下面结合附图6作进一步说明。
步骤203-1:通过比对从所述图形用户界面获取的测试代码和由CSV组件 进行参数替换后的测试代码,获取参数化变量被替换后的具体值。
如上述步骤202-3-3中所述,作为一种优选实施方式,本实施例为了实现测试过程的参数化,为测试代码的runTest()方法添加了入口参数,并对赋值语句中的参数化变量进行了替换。在测试线程初始化之前,即在执行本步骤之前,JMeter的CSV组件针对每个测试线程,根据从本地数据文件中读取的数据行,对测试代码中的参数化变量进行了替换,因此每个测试线程在本步骤中可以获取由CSV组件进行参数替换后的测试代码,并通过与测试人员在JMeter图形用户界面中提供的测试代码(以下简称原始测试代码)的比对,获取参数化变量被替换后的具体值。
具体说,由于在原始测试代码中参数化变量通常采用${}形式,因此本步骤可以通过正则匹配的方式在原始测试代码中定位包含参数化变量的代码行,然后根据已定位的代码行的位置信息,查找CSV替换后的测试代码中的相应代码行,并截取参数化变量被替换后的具体取值。
仍以步骤201中提供的测试代码片段为例,通过正则匹配定位到如下所示的两个代码行:
String userid=${userid};
String ip=${ip};
通过上述两个代码行的位置信息,在CSV替换后的测试代码中找到如下所示的相应代码行:
String userid="1001";
String ip="192.168.1.1";
那么通过上述代码行的比对,本步骤就可以从CSV替换后的测试代码中截取参数化变量的具体参数值"1001"和"192.168.1.1",从而可以在后续的步骤203-2中使用具体的参数值作为入口参数进行web service的服务调用,从而实现测试过程的参数化,使得测试过程更为灵活。需要说明的是,上述例子中给出的变量以及具体参数值都仅仅是示意性的,在具体实施中,测试人员可以根据实际需要定义测试代码中的变量、并且在供CSV读取的本地数据文件中写入所需的参数值。
步骤203-2:使用对应于被测web service的客户端、方法对象以及已获取的具体参数值作为入口参数,调用所述可执行的测试代码完成测试任务。
在本实施例中,由于已经在前置处理阶段统一初始化了对应于被测web service的客户端和方法对象,因此本步骤中可以直接使用已初始化好的客户端和方法对象作为入口参数。
由于本实施例还提供了测试过程参数化的优选实施方式,在步骤202中进行了测试代码的相应修改,在步骤203-2中获取了被CSV替换后的参数化变量的具体取值,因此在本步骤中,还可以将所述参数化变量的具体取值也作为入口参数的一部分。如果在其他实施方式中,不需要实现测试过程的参数化,那么就无需执行上述与参数化相关的代码修改操作、获取参数化变量的具体取值的操作,在本步骤中也不需要在执行服务调用的入口参数中添加相应参数值。
在本实施例中,由于已经在前置处理阶段加载了编译后的.class文件,并且统一初始化了可执行对象,因此本步骤可以采用反射形式直接调用所述可执行对象,完成本次的测试任务。以下为在本实施例的一个具体压力测试例子中,测试线程调用可执行对象的代码片段:
results.sampleStart();
Object result=getScriptMethod().invoke(getScript(),paramProperties);
results.sampleEnd();
在上述代码片段中,getScriptMethod()方法用于获取已初始化的静态的脚本方法对象,getScript()方法用于获取已初始化的静态的脚本对象实例,paramProperties是入口参数列表,其中包括:已初始化的web service客户端和方法对象,以及在步骤203-1中获取的具体的参数值。
步骤203-3:将所述调用操作返回的入口参数信息和结果信息,分别添加到JMeter结果树的request属性及response属性中。
如前面步骤202-3-4所述,如果本实施例采用了在服务调用后将入口参数信息和结果信息一并返回的优选实施方式,在步骤202-3-4中对测试代码中的返回语句进行了相应的修改,那么执行服务调用操作后,本步骤就可以输出返回的上述信息,例如,可以在图形界面或者命令行窗口中显示上述信息、或者将上述信息输出到文件中,以便于进行问题的定位与排查。
由于本实施例是以JMeter插件的形式实施的,而JMeter为了便于测试人员根据测试结果进行问题的定位与排查,提供了多种查看测试结果的方法,例如:图形报表、结果树和聚合报告等。因此本步骤可以通过SampleResult类提供的setSamplerData()方法setResponseData()方法,将执行服务调用返回的入口参数信息和结果信息分别添加到JMeter结果树的request属性和response属性中,从 而在测试结束后,测试人员可以在JMeter结果树界面的“请求”标签页面中查看入口参数信息,在“响应数据”标签页面中查看调用结果信息,并在此基础上进行进一步的问题定位与排查。
每个线程执行上述步骤203-1至步骤203-3,用对应于被测web service的客户端和方法对象作为入口参数,调用所述可执行的测试代码完成测试任务。
在每个线程完成自己的测试任务并退出后,可以在压力测试的后置处理阶段(例如,通过JMeter的后置处理器)完成与测试相关的收尾处理操作。如果在前置处理阶段,修改在步骤201获取的测试代码并生成待编译的java文件,例如wsTest1.java,并且通过编译该文件生成了对应的.class文件,例如wsTest1.class,鉴于压力测试已经结束,因此可以删除上述临时文件wsTest1.java和wsTest1.class文件,以避免临时文件占用过多的存储空间。
综上所述,由于本技术方案内置了支持web service服务调用相关协议的客户端,因此提供测试代码的测试人员无需了解网络协议报文的细节,也不用在协议报文层面进行编码,直接按照预先设定的方式进行web service服务调用即可,从而不仅降低了测试人员的学习成本,而且简化了编写测试代码的工作量,同时也为测试过程的参数化提供了一种简便途径。
在上述的实施例中,提供了一种web service压力测试方法,与之相对应的,本申请还提供一种web service压力测试装置。请参看图7,其为本申请的一种web service压力测试装置的实施例示意图。由于装置实施例基本相似于方法实施例,所以描述得比较简单,相关之处参见方法实施例的部分说明即可。下述描述的装置实施例仅仅是示意性的。
本实施例的一种web service压力测试装置,包括:信息与代码获取单元701,用于获取被测web service的配置信息、以及按照预先设定的方式执行web service服务调用的测试代码;测试预处理单元702,用于在预处理阶段,修改并编译所述测试代码,得到可执行的测试代码;所述修改是指将所述测试代码修改为:根据入口参数提供的客户端以及方法对象执行web service服务调用,其中,所述客户端封装了支持web service服务调用的协议;测试执行单元703,用于在测试执行阶段,每个测试线程使用对应于被测web service的客户端和方法对象作为入口参数,调用所述可执行的测试代码完成测试任务。
可选的,所述信息与代码获取单元获取的被测web service的配置信息包 括:被测服务名称、被测方法名称、以及被测web service的URL信息。
可选的,所述测试预处理单元包括:
代码修改子单元,用于修改所述测试代码,所述修改是指将所述测试代码修改为:根据入口参数提供的客户端以及方法对象执行web service服务调用;
代码编译子单元,用于编译修改后的测试代码,得到可执行的测试代码;
所述测试预处理单元还包括:
客户端初始化子单元,用于根据所述被测web service的配置信息,初始化所述对应于被测web service的客户端和方法对象;
相应的,所述测试执行单元具体用于,每个测试线程使用所述客户端初始化子单元初始化的客户端和方法对象作为入口参数,调用所述可执行的测试代码完成测试任务。
可选的,所述装置以JMeter插件的形式实现;
相应的所述信息与代码获取单元具体用于,通过JMeter的图形用户界面获取所述被测web service的配置信息以及所述测试代码。
可选的,所述代码修改子单元除了包括:
服务调用修改子单元,用于将所述测试代码修改为:根据入口参数提供的客户端以及方法对象执行web service服务调用;
所述代码修改子单元还包括:
自定义参数修改子单元,用于在所述测试代码的入口参数中添加测试所需的自定义参数;
参数化变量替换子单元,用于用所述自定义参数替换所述测试代码中的相应参数化变量;
相应的,所述测试执行单元除了包括:
服务调用子单元,用于每个测试线程使用对应于被测web service的客户端和方法对象作为入口参数,调用所述可执行的测试代码完成测试任务;
所述测试执行单元还包括:
参数值获取子单元,用于在触发所述服务调用子单元之前,每个测试线程通过比对从所述图形用户界面获取的测试代码和由CSV组件进行参数替换后的测试代码,获取参数化变量被替换后的具体值;
相应的,所述测试执行单元所使用的入口参数还包括,所述参数值获取子单元获取的参数化变量被替换后的具体值。
可选的,所述测试执行单元是通过反射方式完成web service服务调用的。
可选的,所述测试预处理单元还包括:
jar包加载子单元,用于在触发所述代码修改子单元之前,将所述测试代码所使用的第三方jar包加载到对应的类加载器中。
可选的,所述代码修改子单元还包括:
返回语句修改子单元,用于修改所述测试代码的返回语句,使其返回信息包括:执行web service服务调用的入口参数信息、以及结果信息。
可选的,所述测试执行单元还包括:
返回信息处理子单元,用于将所述调用操作返回的入口参数信息和结果信息,分别添加到JMeter结果树的request属性及response属性中。
可选的,所述测试预处理单元还包括:
类加载子单元,用于将所述代码编译子单元生成的.class文件显示的加载至对应的类加载器中;
可执行对象初始化子单元,用于根据所述类加载子单元执行加载操作返回的类,通过反射机制初始化可执行对象;
相应的,所述测试执行单元具体用于,每个测试线程调用所述已初始化的可执行对象,完成测试任务。
本申请虽然以较佳实施例公开如上,但其并不是用来限定本申请,任何本领域技术人员在不脱离本申请的精神和范围内,都可以做出可能的变动和修改,因此本申请的保护范围应当以本申请权利要求所界定的范围为准。
在一个典型的配置中,计算设备包括一个或多个处理器(CPU)、输入/输出接口、网络接口和内存。
内存可能包括计算机可读介质中的非永久性存储器,随机存取存储器(RAM)和/或非易失性内存等形式,如只读存储器(ROM)或闪存(flash RAM)。内存是计算机可读介质的示例。
1、计算机可读介质包括永久性和非永久性、可移动和非可移动媒体可以由 任何方法或技术来实现信息存储。信息可以是计算机可读指令、数据结构、程序的模块或其他数据。计算机的存储介质的例子包括,但不限于相变内存(PRAM)、静态随机存取存储器(SRAM)、动态随机存取存储器(DRAM)、其他类型的随机存取存储器(RAM)、只读存储器(ROM)、电可擦除可编程只读存储器(EEPROM)、快闪记忆体或其他内存技术、只读光盘只读存储器(CD-ROM)、数字多功能光盘(DVD)或其他光学存储、磁盒式磁带,磁带磁磁盘存储或其他磁性存储设备或任何其他非传输介质,可用于存储可以被计算设备访问的信息。按照本文中的界定,计算机可读介质不包括非暂存电脑可读媒体(transitory media),如调制的数据信号和载波。
2、本领域技术人员应明白,本申请的实施例可提供为方法、系统或计算机程序产品。因此,本申请可采用完全硬件实施例、完全软件实施例或结合软件和硬件方面的实施例的形式。而且,本申请可采用在一个或多个其中包含有计算机可用程序代码的计算机可用存储介质(包括但不限于磁盘存储器、CD-ROM、光学存储器等)上实施的计算机程序产品的形式。