前天接到了一个测试任务,要求测试一下ES(elsticsearch)在不同并发下的查询效率。如图:

业务场景是在客户端根据具体车牌查询相关车辆信息,结果返回前10条记录。 从图中可以看到,接口的请求参数和返回结果均是JSON字符串,请求可以用POST或者GET方法。先说GET方法:

一、GET方法测试

  1. Insert - New step -选择Custom Request - web_url
  2. 填入相应参数
  3. 生成脚本,并修改如下
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 .

说明:

  1. 返回结果中可以看到检查点和事务都成功了,表明我们的脚本编写无误。
  2. 查看服务器返回的结果需在Vuser-Runtime-settings的log选项下,勾选Enable-logging、Extended log、Data returned by server 。

二、POST方法测试

在用POST方法创建脚本时遇到了点波折——先是使用了函数web_submit_date,执行时报错,查询资料没找到原因,不知道是不是该函数不支持JSON串,有兴趣的可以自己试下。然后尝试用web_custom_request函数,执行后返回的结果都正确,ok,就它了。

  1. Insert - New step -选择Custom Request - web_custom_request
  2. 填入相应参数
  3. 生成脚本,并修改如下(参数中的引号"前需要加斜杠\转译)
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值。
  1. 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接口压力测试的更多相关文章

  1. 使用Loadrunner进行http接口压力测试

    业务描述: 在业务系统里进行查询操作,查询的结果是通过请求http接口,从系统中处理并将结果以json字符串返回. 本文就讲述使用Loadrunner对此类接口进行压力测试并记录相关的性能指标数据: ...

  2. Loadrunner模拟JSON接口请求进行测试

    Loadrunner模拟JSON接口请求进行测试     一.loadrunner脚本创建 1.Insert - New step -选择Custom Request -  web_custom_re ...

  3. Python开发【笔记】:接口压力测试

    接口压力测试脚本 1.单进程多线程模式 # #!/usr/bin/env python # # -*- coding:utf-8 -*- import time import logging impo ...

  4. 学习总结——JMeter做http接口压力测试

    JMeter做http接口压力测试 测前准备 用JMeter做接口的压测非常方便,在压测之前我们需要考虑这几个方面: 场景设定 场景分单场景和混合场景.针对一个接口做压力测试就是单场景,针对一个流程做 ...

  5. 一次接口压力测试qps极低原因分析及解决过程

    一次接口压力测试qps极低原因分析及解决过程 9-2日在做内部的性能测试相关培训时,发现注册接口压力测试qps极低(20左右),这个性能指标远不能达到上线标准 ,经过一系列调试,最后定位 98%的时间 ...

  6. JMeter接口压力测试课程入门到高级实战

    章节一压力测试课程介绍 1.2018年亿级流量压测系列之Jmeter4.0课程介绍和效果演示 简介: 讲解课程安排,使用的Jmeter版本 讲课风格:涉及的组件,操作配置多,不会一次性讲解,会先讲部分 ...

  7. Postman接口&压力测试

    Postman接口与压力测试实例 Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件.它提供功能强大的 Web API & HTTP 请求调试. 1.环境变量和全局 ...

  8. 接口压力测试--Jmeter

    1.Jmeter简介 JMeter就是一个测试工具,相比于LoadRunner等测试工具,此工具免费,且比较好用,但是前提当然是安装Java环境: JMeter可以做 (1)压力测试及性能测试: (2 ...

  9. JMeter做http接口压力测试

    测前准备 用JMeter做接口的压测非常方便,在压测之前我们需要考虑这几个方面: 场景设定 场景分单场景和混合场景.针对一个接口做压力测试就是单场景,针对一个流程做压力测试的时候就是混合场景,需要多个 ...

随机推荐

  1. Android 获取meta-data中的数据

    在 Android 的 Mainfest 清单文件中,Application,Activity,Recriver,Service 的节点中都有这个的存在.很多时候我们可以通过 meta-data 来配 ...

  2. SQL Server 2014 新特性——内存数据库

    SQL Server 2014 新特性——内存数据库 目录 SQL Server 2014 新特性——内存数据库 简介: 设计目的和原因: 专业名词 In-Memory OLTP不同之处 内存优化表 ...

  3. javascript匹配各种括号书写是否正确

    今天在codewars上做了一道题,如下 看上去就是验证三种括号各种嵌套是否正确书写,本来一头雾水,一种括号很容易判断, 但是三种怎么判断! 本人只是个前端菜鸟,,不会什么高深的正则之类的. 于是,在 ...

  4. DBSCAN密度聚类算法

    DBSCAN(Density-Based Spatial Clustering of Applications with Noise,具有噪声的基于密度的聚类方法)是一种很典型的密度聚类算法,和K-M ...

  5. 关于Visual Studio 未能加载各种Package包的解决方案

    问题: 打开Visual Studio 的时候,总提示未能加载相应的Package包,有时候还无法打开项目,各种提示 解决方案: 进入用户目录 C:\Users\用户名\AppData\Local\M ...

  6. Asp.Net Core + Dapper + Repository 模式 + TDD 学习笔记

    0x00 前言 之前一直使用的是 EF ,做了一个简单的小项目后发现 EF 的表现并不是很好,就比如联表查询,因为现在的 EF Core 也没有啥好用的分析工具,所以也不知道该怎么写 Linq 生成出 ...

  7. 【JS基础】循环

    for 循环的语法: for (语句 1; 语句 2; 语句 3) { 被执行的代码块 } 语句 1 在循环(代码块)开始前执行 语句 2 定义运行循环(代码块)的条件 语句 3 在循环(代码块)已被 ...

  8. 在 Windows7 上按照 MySQL5.7

    在 Windows7 上按照 MySQL5.7 1.从官网下载最新版本的 MySQL,这里下载的是 mysql-5.7.17-win32: 2.将下载的 mysql-5.7.17-win32.zip ...

  9. django 学习第一天搭建环境

    目前django版本是1.10,我学习的基础教材是 Web Development with Django Cookbook, Second Edition 搭建好配置环境 ssh免认证登录 修改一下 ...

  10. Atitit.研发管理如何避免公司破产倒闭的业务魔咒

    Atitit.如何避免公司破产倒闭的业务魔咒 1. 大型公司的衰落或者倒闭破产案例1 1.1. 摩托罗拉1 1.2. 诺基亚2 1.3. sun2 2. 为什么他们会倒闭?? 常见的一些倒闭元素2 2 ...