Loadrunner Http Json接口压力测试
前天接到了一个测试任务,要求测试一下ES(elsticsearch)在不同并发下的查询效率。如图:
业务场景是在客户端根据具体车牌查询相关车辆信息,结果返回前10条记录。 从图中可以看到,接口的请求参数和返回结果均是JSON字符串,请求可以用POST或者GET方法。先说GET方法:
一、GET方法测试
- Insert - New step -选择Custom Request - web_url
- 填入相应参数
- 生成脚本,并修改如下
Action()
{
//添加集合点
lr_rendezvous("jihedian");
lr_start_transaction("getTop10");
//插入检查点,检查返回值是否包含kakoTypeName
web_reg_find(
"Search=Body",
"Text=kakoTypeName",
LAST );
//发送get请求
web_url("www.abc.com",
"URL=http://192.168.3.33:9200/_search?{%22query%22:{%22bool%22:{%22must%22:[{%22term%22:{%22plateNumNond%22:%22%E9%B2%81{NewParam}%22}}],%22must_not%22:[],%22should%22:[]}},%22from%22:0,%22size%22:10,%22sort%22:[],%22aggs%22:{}}",
"TargetFrame=",
"Resource=0",
"RecContentType=application/json",
"Snapshot=t1.inf",
"Mode=HTML",
LAST );
lr_end_transaction("getTop10", LR_AUTO);
//打印本次取的车牌号
lr_output_message( "the platenum is #%s", lr_eval_string( "{NewParam}" ) );
return ;
}
4. 查看返回结果
Virtual User Script started at : -- ::
Starting action vuser_init.
Web Turbo Replay of LoadRunner 11.0. for Windows ; build (Aug ::) [MsgId: MMSG-]
Run Mode: HTML [MsgId: MMSG-]
Run-Time Settings file: "F:\PassCarSearch\ESqueryByPlateNumNond_GET\\default.cfg" [MsgId: MMSG-]
Ending action vuser_init.
Running Vuser...
Starting iteration .
Starting action Action.
Action.c(): Rendezvous jihedian
Action.c(): Notify: Transaction "getTop10" started.
Action.c(): Registering web_reg_find was successful [MsgId: MMSG-]
Action.c(): Registered web_reg_find successful for "Text=kakoTypeName" (count=) [MsgId: MMSG-]
Action.c(): web_url("www.abc.com") was successful, body bytes, header bytes [MsgId: MMSG-]
Action.c(): Notify: Transaction "getTop10" ended with "Pass" status (Duration: 3.1371 Wasted Time: 0.4776).
Action.c(): the platenum is #UT5387
Ending action Action.
Ending iteration .
说明:
- 返回结果中可以看到检查点和事务都成功了,表明我们的脚本编写无误。
- 查看服务器返回的结果需在Vuser-Runtime-settings的log选项下,勾选Enable-logging、Extended log、Data returned by server 。
二、POST方法测试
在用POST方法创建脚本时遇到了点波折——先是使用了函数web_submit_date,执行时报错,查询资料没找到原因,不知道是不是该函数不支持JSON串,有兴趣的可以自己试下。然后尝试用web_custom_request函数,执行后返回的结果都正确,ok,就它了。
- Insert - New step -选择Custom Request - web_custom_request
- 填入相应参数
- 生成脚本,并修改如下(参数中的引号"前需要加斜杠\转译)
Action()
{
lr_start_transaction("querybypost");
//插入检查点,检查返回值是否包含t_query_data
web_reg_find(
"Text=max_score",
LAST );
web_custom_request("querybypost", //VuGen中树形视图中显示的名称
"Url=http://192.168.3.33:9200/_search", //请求url
"Method=POST",
"Resource=0",
"Mode=HTTP", //请求方式
"Referer=",
"EncType=application/json", //指定响应头的Content-Type,这里是JSON
"RecContentType=application/json", //指定请求头的Content-Type,这里是JSON
"Body={\"query\":{\"bool\":{\"must\":[{\"term\":{\"plateNumNond\":\"<PlateNumNond>\"}}],\"must_not\":[],\"should\":[]}},\"from\":0,\"size\":10,\"sort\":[],\"aggs\":{}}:", //body的内容
LAST);
lr_end_transaction("querybypost", LR_AUTO);
lr_output_message( "PlateNumNond on iteration #%s", lr_eval_string( "<PlateNumNond>" ) );
}
4. 查看返回结果
Virtual User Script started at : -- ::
Starting action vuser_init.
Web Turbo Replay of LoadRunner 11.0. for Windows ; build (Aug ::) [MsgId: MMSG-]
Run Mode: HTML [MsgId: MMSG-]
Run-Time Settings file: "F:\PassCarSearch\ESqueryByPlateNumNond_POST\\default.cfg" [MsgId: MMSG-]
Ending action vuser_init.
Running Vuser...
Starting iteration .
Starting action Action.
Action.c(): Notify: Transaction "querybypost" started.
Action.c(): Registering web_reg_find was successful [MsgId: MMSG-]
Action.c(): Warning: The string '"plateNumNond":"B23456"' with parameter delimiters is not a parameter.
Action.c(): Warning: The string '' with parameter delimiters is not a parameter.
Action.c(): t=770ms: -byte response headers for "http://192.168.3.33:9200/_search" (RelFrameId=, Internal ID=)
Action.c(): HTTP/1.1 OK\r\n
Action.c(): Content-Type: application/json; charset=UTF-\r\n
Action.c(): Content-Length: \r\n
Action.c(): \r\n
Action.c(): t=808ms: -byte response body for "http://192.168.3.33:9200/_search" (RelFrameId=, Internal ID=)
Action.c(): {"took":,"timed_out":false,"_shards":{"total":,"successful":,"failed":},"hits":{"tot
Action.c(): al":0,"max_score":null,"hits":[]}}
Action.c(): Error -: "Text=t_query_data" not found for web_reg_find [MsgId: MERR-]
Action.c(): web_custom_request("querybypost") highest severity level was "ERROR", body bytes, header bytes [MsgId: MMSG-]
Action.c(): Notify: Transaction "querybypost" ended with "Fail" status (Duration: 0.9686 Wasted Time: 0.7094).
Ending action Action.
Ending iteration .
Ending Vuser...
Starting action vuser_end.
Ending action vuser_end.
Vuser Terminated.
好吧,报错了。返回结果中的提示是Warning: The string '"plateNumNond":"B23456"' with parameter delimiters is not a parameter.
本着有问题找度娘的一贯态度,将这句话复制到度娘中检索,但结果不遂人愿,没有查询到解决思路。中间不断的思考是不是自己的代码出了问题,但最终把怀疑一一排除。后来突然想到在loadrunner中,参数化的标志是{},我在body里面的{}并不是参数化,而是json的格式。。。终于找到原因了,接下来就简单了,只需在Tool - General Options - Parameterization 中将Parameter Braces 改为<>即可,如图
5. 重新运行,查看结果。 看到以下结果,ok,搞定,收工!
Virtual User Script started at : -- ::
Starting action vuser_init.
Web Turbo Replay of LoadRunner 11.0. for Windows ; build (Aug ::) [MsgId: MMSG-]
Run Mode: HTML [MsgId: MMSG-]
Run-Time Settings file: "F:\PassCarSearch\ESqueryByPlateNumNond_POST\\default.cfg" [MsgId: MMSG-]
Ending action vuser_init.
Running Vuser...
Starting iteration .
Starting action Action.
Action.c(): Notify: Transaction "querybypost" started.
Action.c(): Registering web_reg_find was successful [MsgId: MMSG-]
Action.c(): Notify: Parameter Substitution: parameter "PlateNumNond" = "鲁UTR294"
Action.c(): t=1729ms: -byte response headers for "http://192.168.3.33:9200/_search" (RelFrameId=, Internal ID=)
Action.c(): HTTP/1.1 OK\r\n
Action.c(): Content-Type: application/json; charset=UTF-\r\n
Action.c(): Content-Length: \r\n
Action.c(): \r\n
Action.c(): t=1885ms: -byte response body for "http://192.168.3.33:9200/_search" (RelFrameId=, Internal ID=)
Action.c(): {"took":,"timed_out":false,"_shards":{"total":,"successful":,"failed":},"hits":{"tot
Action.c(): al":0,"max_score":null,"hits":[]}}
Action.c(): Registered web_reg_find successful for "Text=max_score" (count=) [MsgId: MMSG-]
Action.c(): web_custom_request("querybypost") was successful, body bytes, header bytes [MsgId: MMSG-]
Action.c(): Notify: Transaction "querybypost" ended with "Pass" status (Duration: 1.8611 Wasted Time: 0.6362).
Action.c(): Notify: Parameter Substitution: parameter "PlateNumNond" = "鲁UTR294"
Action.c(): PlateNumNond on iteration #鲁UTR294
Ending action Action.
Ending iteration .
三、web_custom_request和web_submit_data区别
在解决问题的过程中查询了web_custom_request和web_submit_data区别,现附录如下:
- web_custom_request方法可以发送POST和GET类型的请求;
- web_submit_data只能发送POST类型的请求;
- 所有web_submit_data方法发送的请求都可以使用web_custom_request来实现
- web_custom_request可以实现web_submit_data无法实现的请求,比如“查询所有邮件并删除”这个案例中,查询时我们使用关联把所有邮件对应的标识抓取成一个数组,如果使用web_submit_data来完成这个删除的请求,需要很多个web_submit_data请求才能完成,但使用web_custom_request就可以通过一个请求完成,方法是自己写代码拼一个eb_custom_request
- 方法POST请求的Body值。
- web_submit_data
请求中提交的数据格式:“Name=属性名称,”,“Value=属性值”
例如:
"Name=username″,"Value=″,
ENDITEM,
"Name=password″,"Value=″,
ENDITEM,
"Name=typeId″,"Value=″,
ENDITEM,
如果想提交的某个属性包含包含多个值(比如说批量删除),单个web_submit_data就无法处理了,只能通过多个web_submit_data来处理。
2. web_custom_request
提交的数据(body)格式:“Body=属性名称=属性值&属性名称=属性值&……”
下面是一个典型的web_submit_data和web_custom_request请求,可以看到web_custom_request中提交的数据(body)是以这样的方式存在的,如下:
web_submit_data("searchRecvOrgsname",
"Action=http://{url}/searchRecvOrgsname",
"Method=POST",
"TargetFrame=",
"RecContentType=text/html",
"Referer=http://{url}/login_wj;jsessionid={jsessionid}",
"Snapshot=t18.inf",
"Mode=HTML",
ITEMDATA,
"Name=orgsId",
"Value={orgsId}", ENDITEM,
"Name=code",
"Value={order_end_station_code}", ENDITEM,
LAST);
web_custom_request("searchVehiclePopUp",
"URL=http://{url}/searchVehiclePopUp",
"Method=POST",
"TargetFrame=",
"Resource=0",
"RecContentType=text/html",
"Referer=http://{url}/login_wanjia;jsessionid={jsessionid}",
"Snapshot=t19.inf",
"Mode=HTML",
"EncType=application/x-www-form-urlencoded;
charset=UTF-",
"Body=&orgsId={orgsId}&order_start_station_id={order_start_station_id}&targetcode=order_truck_no&targetname=order_truck_name&targetid=order_truck_id",
LAST);
两种情况下的POST请求会被LoadRunner录制为web_custom_request:
- 上文提到的批量提交多条同属性名称的数据的请求
- header属性x-requested-by值为XMLHttpRequest的POST请求
这两种实现请求的方法还有一个需要注意的地方就是web_custom_request中body中的属性值如果包含一些特殊字符,必须通过URL编码,否则Web服务器会返回500错误,一个典型的例子是如果Body中包含ViewState,ViewState中常常有“=”之类的特殊字符,此时必须通过URL编码,LoadRuner中提供了一个这样的编码转换函数:
web_convert_param(“vs1″,
“SourceEncoding=HTML”,“TargetEncoding=URL”, LAST);
3. web_custom_request函数详解
A.语法:
int web_custom_request( const char
*RequestName, ,
[EXTRARES, ,] LAST );
B.返回值:返回LR_PASS(0)代表成功,LR_FAIL(1)代表失败。
C.参数:
(1)RequestName:步骤的名称,VuGen中树形视图中显示的名称。
(2)List of Attribute:属性列表,支持的属性有以下几种:
a. URL:页面地址。
b. Method:页面的提交方式,POST或GET。
c. EncType:编码类型。
d. TargetFrame:当前链接或资源所在Frame的名称。
除了Frame的名字,还可以指定下面的参数:
_BLANK:打开一个空窗口。
_PARENT:把最新更改过的的Frame替换为它的上级。
_SELF:替换最新更改过的的Frame。
_TOP:替换整个页面。
Loadrunner Http Json接口压力测试的更多相关文章
- 使用Loadrunner进行http接口压力测试
业务描述: 在业务系统里进行查询操作,查询的结果是通过请求http接口,从系统中处理并将结果以json字符串返回. 本文就讲述使用Loadrunner对此类接口进行压力测试并记录相关的性能指标数据: ...
- Loadrunner模拟JSON接口请求进行测试
Loadrunner模拟JSON接口请求进行测试 一.loadrunner脚本创建 1.Insert - New step -选择Custom Request - web_custom_re ...
- Python开发【笔记】:接口压力测试
接口压力测试脚本 1.单进程多线程模式 # #!/usr/bin/env python # # -*- coding:utf-8 -*- import time import logging impo ...
- 学习总结——JMeter做http接口压力测试
JMeter做http接口压力测试 测前准备 用JMeter做接口的压测非常方便,在压测之前我们需要考虑这几个方面: 场景设定 场景分单场景和混合场景.针对一个接口做压力测试就是单场景,针对一个流程做 ...
- 一次接口压力测试qps极低原因分析及解决过程
一次接口压力测试qps极低原因分析及解决过程 9-2日在做内部的性能测试相关培训时,发现注册接口压力测试qps极低(20左右),这个性能指标远不能达到上线标准 ,经过一系列调试,最后定位 98%的时间 ...
- JMeter接口压力测试课程入门到高级实战
章节一压力测试课程介绍 1.2018年亿级流量压测系列之Jmeter4.0课程介绍和效果演示 简介: 讲解课程安排,使用的Jmeter版本 讲课风格:涉及的组件,操作配置多,不会一次性讲解,会先讲部分 ...
- Postman接口&压力测试
Postman接口与压力测试实例 Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件.它提供功能强大的 Web API & HTTP 请求调试. 1.环境变量和全局 ...
- 接口压力测试--Jmeter
1.Jmeter简介 JMeter就是一个测试工具,相比于LoadRunner等测试工具,此工具免费,且比较好用,但是前提当然是安装Java环境: JMeter可以做 (1)压力测试及性能测试: (2 ...
- JMeter做http接口压力测试
测前准备 用JMeter做接口的压测非常方便,在压测之前我们需要考虑这几个方面: 场景设定 场景分单场景和混合场景.针对一个接口做压力测试就是单场景,针对一个流程做压力测试的时候就是混合场景,需要多个 ...
随机推荐
- Android SwipeRefreshLayout 下拉刷新——Hi_博客 Android App 开发笔记
以前写下拉刷新 感觉好费劲,要判断ListView是否滚到顶部,还要加载头布局,还要控制 头布局的状态,等等一大堆.感觉麻烦死了.今天学习了SwipeRefreshLayout 的用法,来分享一下,有 ...
- JavaScript function函数种类
本篇主要介绍普通函数.匿名函数.闭包函数 目录 1. 普通函数:介绍普通函数的特性:同名覆盖.arguments对象.默认返回值等. 2. 匿名函数:介绍匿名函数的特性:变量匿名函数.无名称匿名函数. ...
- 【项目管理】GitHub使用操作指南
GitHub使用操作指南 作者:白宁超 2016年10月5日18:51:03> 摘要:GitHub的是版本控制和协作代码托管平台,它可以让你和其他人的项目从任何地方合作.相对于CVS和SVN的联 ...
- JQuery(2)
JQuery下拉框操作: 取值赋值操作 body代码: <select id="sel"> <option value="北京">北京& ...
- php批量删除
php批量删除可以实现多条或者全部数据一起删除 新建php文件 显示数据库中内容: <table width="100%" border="1" cell ...
- HTML简单入门内容
常用属性: Width=宽度 Height=高度 Size=大小 Color=颜色 Align=布局方向,值包括(top,bottom,left,right,center)上,下,左,右,中. Bor ...
- React Native Android gradle下载慢问题解决
很多人会遇到 初次运行 react-native run android的时候 gradle下载极慢,甚至会失败的问题 如下图 实际上这个问题好解决的 首先 把对应版本的gradle下载到本地任意一个 ...
- Atitit.研发管理软件公司的软资产列表指南
Atitit.研发管理软件公司的软资产列表指南 1. Isv模型下的软资产1 2. 实现层面implet1 3. 规范spec层1 4. 法则定律等val层的总结2 1. Isv模型下的软资产 Sof ...
- Linux 利用Google Authenticator实现ssh登录双因素认证
1.介绍 双因素认证:双因素身份认证就是通过你所知道再加上你所能拥有的这二个要素组合到一起才能发挥作用的身份认证系统.双因素认证是一种采用时间同步技术的系统,采用了基于时间.事件和密钥三变量而产生的一 ...
- excel常用技巧
复制表格时,如果要加上行标和列标.页面布局->工作表选项:标题,勾上打印->复制下拉框->复制为图片加上打印样式 一行长拆成几行短或几行短变成一行长的文本拆分,可以通过:填充-> ...