打开Virtual User Generator
创建脚本,协议选择Web - HTTP/HTML,输入脚本名,选择好脚本存放路径,点击create即可创建好一个空白脚本。
设置录制选项,点击record按钮,设置完基本信息后,点击右下角的Recording Options,设置录制选项:
开始录制:录制选项设置完成后,点击Start Recording即可开始录制。
录制完整的登录->查询航班->选择航班->支付->查看结果->退出登录流程
登录之前先插入一个登录事务:tran01_login,然后输入用户/密码(jojo/bean),点击登录:
登录完成后,结束登录事务:
先点击页面上的Flights,进入查找航班界面,然后插入事务:tran02_findFlight,输入航班信息后,点击continue按钮进入下一步
点击按钮后,结束tran02_findFlight事务。
插入事务:trans03_selectFlight,选择航班,然后点击continue,进入下一步
结束trans03_selectFlight事务
插入事务:trans04_payment,输入支付信息后,然后点击continue,进入下一步
结束trans04_payment事务
插入事务:trans05_itinerary,点击Itinerary,查看预定结果
结束trans05_itinerary事务
插入事务:trans06_signOff,点击sign Off按钮退出登录:
结束trans06_signOff事务。
至此,整个预定流程完成,点击结束录制按钮,完成录制,生成录制脚本。
完整的录制脚本如下:
Action()
{
//打开WebTours主页
web_url("index.htm",
"URL=http://127.0.0.1:1080/WebTours/index.htm",
"Resource=0",
"RecContentType=text/html",
"Referer=",
"Snapshot=t1.inf",
"Mode=HTML",
LAST);
lr_think_time(13);
//登录
lr_start_transaction("tran01_login");
web_submit_data("login.pl",
"Action=http://127.0.0.1:1080/cgi-bin/login.pl",
"Method=POST",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/nav.pl?in=home",
"Snapshot=t4.inf",
"Mode=HTML",
ITEMDATA,
"Name=userSession", "Value=133951.489509923ziQAVcQpHtVzzzzHtVDtApHHitf", ENDITEM,
"Name=username", "Value=jojo", ENDITEM,
"Name=password", "Value=bean", ENDITEM,
"Name=JSFormSubmit", "Value=on", ENDITEM,
"Name=login.x", "Value=51", ENDITEM,
"Name=login.y", "Value=10", ENDITEM,
LAST);
lr_end_transaction("tran01_login",LR_AUTO);
lr_think_time(13);
//查询航班
lr_start_transaction("tran02_findFlight");
web_submit_data("reservations.pl",
"Action=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Method=POST",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/reservations.pl?page=welcome",
"Snapshot=t9.inf",
"Mode=HTML",
ITEMDATA,
"Name=advanceDiscount", "Value=0", ENDITEM,
"Name=depart", "Value=Denver", ENDITEM,
"Name=departDate", "Value=05/28/2022", ENDITEM,
"Name=arrive", "Value=Frankfurt", ENDITEM,
"Name=returnDate", "Value=05/29/2022", ENDITEM,
"Name=numPassengers", "Value=1", ENDITEM,
"Name=seatPref", "Value=Window", ENDITEM,
"Name=seatType", "Value=First", ENDITEM,
"Name=.cgifields", "Value=roundtrip", ENDITEM,
"Name=.cgifields", "Value=seatType", ENDITEM,
"Name=.cgifields", "Value=seatPref", ENDITEM,
"Name=findFlights.x", "Value=65", ENDITEM,
"Name=findFlights.y", "Value=5", ENDITEM,
LAST);
lr_end_transaction("tran02_findFlight",LR_AUTO);
lr_think_time(21);
//选择航班
lr_start_transaction("trans03_selectFlight");
web_submit_data("reservations.pl_2",
"Action=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Method=POST",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Snapshot=t10.inf",
"Mode=HTML",
ITEMDATA,
"Name=outboundFlight", "Value=013;592;05/28/2022", ENDITEM,
"Name=numPassengers", "Value=1", ENDITEM,
"Name=advanceDiscount", "Value=0", ENDITEM,
"Name=seatType", "Value=First", ENDITEM,
"Name=seatPref", "Value=Window", ENDITEM,
"Name=reserveFlights.x", "Value=52", ENDITEM,
"Name=reserveFlights.y", "Value=9", ENDITEM,
LAST);
lr_end_transaction("trans03_selectFlight",LR_AUTO);
lr_think_time(26);
//支付
lr_start_transaction("trans04_payment");
web_submit_data("reservations.pl_3",
"Action=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Method=POST",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Snapshot=t11.inf",
"Mode=HTML",
ITEMDATA,
"Name=firstName", "Value=Jojo", ENDITEM,
"Name=lastName", "Value=Bean", ENDITEM,
"Name=address1", "Value=123", ENDITEM,
"Name=address2", "Value=456", ENDITEM,
"Name=pass1", "Value=Jojo Bean", ENDITEM,
"Name=creditCard", "Value=123456", ENDITEM,
"Name=expDate", "Value=1122", ENDITEM,
"Name=saveCC", "Value=on", ENDITEM,
"Name=oldCCOption", "Value=on", ENDITEM,
"Name=numPassengers", "Value=1", ENDITEM,
"Name=seatType", "Value=First", ENDITEM,
"Name=seatPref", "Value=Window", ENDITEM,
"Name=outboundFlight", "Value=013;592;05/28/2022", ENDITEM,
"Name=advanceDiscount", "Value=0", ENDITEM,
"Name=returnFlight", "Value=", ENDITEM,
"Name=JSFormSubmit", "Value=off", ENDITEM,
"Name=.cgifields", "Value=saveCC", ENDITEM,
"Name=buyFlights.x", "Value=42", ENDITEM,
"Name=buyFlights.y", "Value=10", ENDITEM,
LAST);
lr_end_transaction("trans04_payment",LR_AUTO);
lr_think_time(16);
//查询预定结果
lr_start_transaction("trans05_itinerary");
web_url("welcome.pl",
"URL=http://127.0.0.1:1080/cgi-bin/welcome.pl?page=itinerary",
"Resource=0",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/nav.pl?page=menu&in=flights",
"Snapshot=t12.inf",
"Mode=HTML",
LAST);
lr_end_transaction("trans05_itinerary",LR_AUTO);
lr_think_time(19);
//退出登录
lr_start_transaction("trans06_signOff");
web_url("welcome.pl_3",
"URL=http://127.0.0.1:1080/cgi-bin/welcome.pl?signOff=1",
"Resource=0",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/nav.pl?page=menu&in=itinerary",
"Snapshot=t13.inf",
"Mode=HTML",
LAST);
lr_end_transaction("trans06_signOff",LR_AUTO);
return 0;
}
点击Replay,回放脚本:
作用:将服务器返回给客户端的动态值进行关联。
回放成功后,可以登录WebTours查看预定的记录是否增加了一条,如果增加了,说明脚本没问题,可以成功预定。然而登录后,发现预定的数量并没有增加。所以,需要重新检查脚本。
首先是检查登录是否成功。可以看到登录的web_submit_data方法中,提交的参数有userSession,userSession为动态为动态生成,userSession在第一次请求服务器的时候有服务器返回,所以需要对该参数做参数关联。
要获取userSession有两个方法:
可以看到nav.pl?in=home请求中,返回报文中包含userSession:
<input type="hidden" name="userSession" value="133944.089590928ziiQHtQpVAiDDDDDtVDDiptQtzf"/>
找到userSession后,即可开始编写关联函数,关联函数为web_reg_save_param(),具体如下:
//设置userSession参数关联
web_reg_save_param("userSession", //参数名
"LB=name=\"userSession\" value=\"", //左边界:参数值的左边字符,如果带有双引号,需要用\进行转义
"RB=\"/>", //右边界:参数值的右边字符,根据左右边界可以唯一确定参数值
LAST);
注意关联需要写到操作函数的上面,关联函数编写完成后,需要替换脚本中的参数值,将登录时的提交参数替换如下:
web_submit_data("login.pl",
"Action=http://127.0.0.1:1080/cgi-bin/login.pl",
"Method=POST",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/nav.pl?in=home",
"Snapshot=t42.inf",
"Mode=HTML",
ITEMDATA,
"Name=userSession", "Value={userSession}", ENDITEM, //参数关联,参数名需要用{}括起来
"Name=username", "Value=jojo", ENDITEM,
"Name=password", "Value=bean", ENDITEM,
"Name=JSFormSubmit", "Value=on", ENDITEM,
"Name=login.x", "Value=42", ENDITEM,
"Name=login.y", "Value=12", ENDITEM,
LAST);
关联完成后,重新回放,然后登录网站检查,可以看到Itinerary中订单多了一个记录,每回放一次都会多一条,说明关联成功,脚本可以正常完成登录了。
在该脚本中,所有参数均是固定的,比如订票操作,每次都是订的Denver->Frankfurt,如果想要每次预定都使用不同的出发/到达城市对,则需要进行对响应的数据进行参数化,具体操作参考:https://blog.csdn.net/weixin_42115131/article/details/124965795
设置好的脚本如下:
web_submit_data("reservations.pl",
"Action=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Method=POST",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/reservations.pl?page=welcome",
"Snapshot=t47.inf",
"Mode=HTML",
ITEMDATA,
"Name=advanceDiscount", "Value=0", ENDITEM,
"Name=depart", "Value={depart}", ENDITEM, //出发城市参数化
"Name=departDate", "Value=05/27/2022", ENDITEM,
"Name=arrive", "Value={arrive}", ENDITEM, //到达城市参数化
"Name=returnDate", "Value=05/28/2022", ENDITEM,
"Name=numPassengers", "Value=1", ENDITEM,
"Name=seatPref", "Value=Window", ENDITEM,
"Name=seatType", "Value=Business", ENDITEM,
"Name=.cgifields", "Value=roundtrip", ENDITEM,
"Name=.cgifields", "Value=seatType", ENDITEM,
"Name=.cgifields", "Value=seatPref", ENDITEM,
"Name=findFlights.x", "Value=63", ENDITEM,
"Name=findFlights.y", "Value=8", ENDITEM,
LAST);
参数设置时,Select next row框选取Unique和Sequential有如下区别,以10个虚拟用户迭代10次为例:
当选择Sequential时,可以看到,同一个每个虚拟用户取值相同,下一次迭代取第二个参数,第6次迭代参数已取完,重新循环取第一个值:
当选择Unique时,表示每个虚拟用户取唯一的一个值,每次迭代每个虚拟用户都会取不同参数值,由于只设置了5个虚拟用户,所以后5个虚拟用户未取到值:
替换参数后,重新运行脚本,在runtime setting中将迭代设置为5次,完成后登录网站查看是否生成了5个不同城市对的订单
可以看出,生成的5个记录全是Denver/Frankfurt。参数化并未生效。
再次检查脚本,发现查询航班完成后的选择航班提交的数据,outboundFlight为013;592;05/28/2022,即不论查询结果是什么,每次选择的航班都是013号,592$,该值为查询航班时由服务器返回的值,所以,还需要对该值做参数关联,关联方法同userSession:
web_reg_save_param("outboundFlight",
"LB=name=\"outboundFlight\" value=\"",
"RB=\">",
"Ord=2", //相同的左右边界共有4个,取第二个
LAST);
关联之后,把后面脚本中出现该参数的地方都用关联的参数替换掉,然后重新执行脚本,检查结果:
可以看到,成功预定了5张不同出发到达城市对的票。
订票成功后,页面上会返回字符串”Thank you for booking through Web Tours.“,这儿介绍两种设置检查点的方法:
参考:https://blog.csdn.net/weixin_42115131/article/details/124965795
原理和参数关联一致,先将服务器返回的参数保存下来:
<small><B>Thank you for booking through Web Tours.B>small>
web_reg_save_param("response",
"LB=",
"RB=",
LAST);
在payment之后,对服务器返回值和预期值做对比:
//检查支付是否成功
if(strstr(lr_eval_string("{payment_result}"), "Thank you for booking through Web Tours.")!=NULL){
//strstr(str1, str2)为c语言函数,如果str2为str1子串,则返回字串出现的位置;不是则返回NULL
//lr_eval_string()函数作用为返回脚本中的一个参数当前的值,格式为:lr_eval_string("{参数名}");
lr_end_transaction("trans04_payment",LR_PASS);
//事务有3种结束状态,LR_AUTO为自动结束,不判断成功失败;LR_FAIL为以失败的状态结束;LR_PASS为以成功的状态结束
lr_output_message("Success! depart is %s, arrive is %s.", lr_eval_string("{depart}"), lr_eval_string("{arrive}"));
//lr_output_message为打印函数
}else{
lr_end_transaction("trans04_payment",LR_PASS);
lr_output_message("FAIL!!!!!!");
}
加入检查点后,重新运行,结果如下:
Action.c(149): Success! depart is Portland, arrive is Denver.
Action.c(149): Success! depart is San Francisco, arrive is Frankfurt.
Action.c(149): Success! depart is Seattle, arrive is London.
Action.c(149): Success! depart is Sydney, arrive is Los Angeles.
Action.c(149): Success! depart is Zurich, arrive is Paris.
至此,脚本调试完成,可以将脚本加载到controller中设置场景执行。完整脚本如下:
Action()
{
//设置userSession参数关联
web_reg_save_param("userSession", //参数名
"LB=name=\"userSession\" value=\"", //左边界:参数值的左边字符,如果带有双引号,需要用\进行转义
"RB=\"/>", //右边界:参数值的右边字符,根据左右边界可以唯一确定参数值
LAST);
//打开WebTours主页
web_url("index.htm",
"URL=http://127.0.0.1:1080/WebTours/index.htm",
"Resource=0",
"RecContentType=text/html",
"Referer=",
"Snapshot=t1.inf",
"Mode=HTML",
LAST);
lr_think_time(13);
//登录
lr_start_transaction("tran01_login");
web_submit_data("login.pl",
"Action=http://127.0.0.1:1080/cgi-bin/login.pl",
"Method=POST",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/nav.pl?in=home",
"Snapshot=t4.inf",
"Mode=HTML",
ITEMDATA,
"Name=userSession", "Value={userSession}", ENDITEM,
"Name=username", "Value=jojo", ENDITEM,
"Name=password", "Value=bean", ENDITEM,
"Name=JSFormSubmit", "Value=on", ENDITEM,
"Name=login.x", "Value=51", ENDITEM,
"Name=login.y", "Value=10", ENDITEM,
LAST);
lr_end_transaction("tran01_login",LR_AUTO);
lr_think_time(13);
//查询航班
lr_start_transaction("tran02_findFlight");
//设置outboundFlight关联函数
web_reg_save_param("outboundFlight",
"LB=name=\"outboundFlight\" value=\"",
"RB=\">",
"Ord=2", //相同的左右边界共有4个,取第二个
LAST);
web_submit_data("reservations.pl",
"Action=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Method=POST",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/reservations.pl?page=welcome",
"Snapshot=t9.inf",
"Mode=HTML",
ITEMDATA,
"Name=advanceDiscount", "Value=0", ENDITEM,
"Name=depart", "Value={depart}", ENDITEM,
"Name=departDate", "Value=05/28/2022", ENDITEM,
"Name=arrive", "Value={arrive}", ENDITEM,
"Name=returnDate", "Value=05/29/2022", ENDITEM,
"Name=numPassengers", "Value=1", ENDITEM,
"Name=seatPref", "Value=Window", ENDITEM,
"Name=seatType", "Value=First", ENDITEM,
"Name=.cgifields", "Value=roundtrip", ENDITEM,
"Name=.cgifields", "Value=seatType", ENDITEM,
"Name=.cgifields", "Value=seatPref", ENDITEM,
"Name=findFlights.x", "Value=65", ENDITEM,
"Name=findFlights.y", "Value=5", ENDITEM,
LAST);
lr_end_transaction("tran02_findFlight",LR_AUTO);
lr_think_time(21);
//选择航班
lr_start_transaction("trans03_selectFlight");
web_submit_data("reservations.pl_2",
"Action=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Method=POST",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Snapshot=t10.inf",
"Mode=HTML",
ITEMDATA,
"Name=outboundFlight", "Value={outboundFlight}", ENDITEM,
"Name=numPassengers", "Value=1", ENDITEM,
"Name=advanceDiscount", "Value=0", ENDITEM,
"Name=seatType", "Value=First", ENDITEM,
"Name=seatPref", "Value=Window", ENDITEM,
"Name=reserveFlights.x", "Value=52", ENDITEM,
"Name=reserveFlights.y", "Value=9", ENDITEM,
LAST);
lr_end_transaction("trans03_selectFlight",LR_AUTO);
lr_think_time(26);
//支付
lr_start_transaction("trans04_payment");
//保存返回的参数,做事务状态检查
web_reg_save_param("payment_result",
"LB=",
"RB=",
LAST);
web_submit_data("reservations.pl_3",
"Action=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Method=POST",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/reservations.pl",
"Snapshot=t11.inf",
"Mode=HTML",
ITEMDATA,
"Name=firstName", "Value=Jojo", ENDITEM,
"Name=lastName", "Value=Bean", ENDITEM,
"Name=address1", "Value=123", ENDITEM,
"Name=address2", "Value=456", ENDITEM,
"Name=pass1", "Value=Jojo Bean", ENDITEM,
"Name=creditCard", "Value=123456", ENDITEM,
"Name=expDate", "Value=1122", ENDITEM,
"Name=saveCC", "Value=on", ENDITEM,
"Name=oldCCOption", "Value=on", ENDITEM,
"Name=numPassengers", "Value=1", ENDITEM,
"Name=seatType", "Value=First", ENDITEM,
"Name=seatPref", "Value=Window", ENDITEM,
"Name=outboundFlight", "Value={outboundFlight}", ENDITEM,
"Name=advanceDiscount", "Value=0", ENDITEM,
"Name=returnFlight", "Value=", ENDITEM,
"Name=JSFormSubmit", "Value=off", ENDITEM,
"Name=.cgifields", "Value=saveCC", ENDITEM,
"Name=buyFlights.x", "Value=42", ENDITEM,
"Name=buyFlights.y", "Value=10", ENDITEM,
LAST);
//检查支付是否成功
if(strstr(lr_eval_string("{payment_result}"), "Thank you for booking through Web Tours.")!=NULL){
//strstr(str1, str2)为c语言函数,如果str2为str1子串,则返回字串出现的位置;不是则返回NULL
//lr_eval_string()函数作用为返回脚本中的一个参数当前的值,格式为:lr_eval_string("{参数名}");
lr_end_transaction("trans04_payment",LR_PASS);
//事务有3种结束状态,LR_AUTO为自动结束,不判断成功失败;LR_FAIL为以失败的状态结束;LR_PASS为以成功的状态结束
lr_output_message("Success! depart is %s, arrive is %s.", lr_eval_string("{depart}"), lr_eval_string("{arrive}"));
//lr_output_message为打印函数
}else{
lr_end_transaction("trans04_payment",LR_PASS);
lr_output_message("FAIL!!!!!!");
}
lr_think_time(16);
//查询预定结果
lr_start_transaction("trans05_itinerary");
web_url("welcome.pl",
"URL=http://127.0.0.1:1080/cgi-bin/welcome.pl?page=itinerary",
"Resource=0",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/nav.pl?page=menu&in=flights",
"Snapshot=t12.inf",
"Mode=HTML",
LAST);
lr_end_transaction("trans05_itinerary",LR_AUTO);
lr_think_time(19);
//退出登录
lr_start_transaction("trans06_signOff");
web_url("welcome.pl_3",
"URL=http://127.0.0.1:1080/cgi-bin/welcome.pl?signOff=1",
"Resource=0",
"RecContentType=text/html",
"Referer=http://127.0.0.1:1080/cgi-bin/nav.pl?page=menu&in=itinerary",
"Snapshot=t13.inf",
"Mode=HTML",
LAST);
lr_end_transaction("trans06_signOff",LR_AUTO);
return 0;
}