目录
项目的截图
商品列表页
购物车页
订单详情页
我的订单页
测试的流程
上面的商城项目是JavaWeb的课程作业,这学期上软件测试的课程需要用来做测试。下面简单介绍一下,录制的测试脚本的主要流程。
- 在 "商品列表页" 挑选商品,并点击 "加入购物车" 按钮,将商品添加到购物车。
- 挑选商品完毕后,在 "购物车页面" 选择要结算的商品,并点击 "结算" 按钮。
- 跳转到 "订单详情页",填写订单信息,并点击 "增加订单" 按钮,生成订单。
- 在 "我的订单页面" 点击 "支付" 按钮。
脚本replay报错分析
录制出来脚本,在 "replay" 的时候出现问题。结合后端代码,分析整个流程,定位问题根源。
1、数据库中有一张关键的表 cart_item (用来描述购物车的)
- user_id:用户id(比如说A)
- pid:商品id(比如说B)
- num:用户A将多少件商品B放入到自己的购物车
- cartID:自增长id
2、当用户A将商品B放入到购物车中时,假如用户A的购物车中不存在商品B(cart_item表没有user_id为A,pid为B的记录),则插入一条新记录。假如对应记录,则将对应记录的 num 加 1。
3、用户在购物车页面点击 "结算" 按钮时,会将勾选对应的商品的 cartID (多个)传递到 "订单详情页"。在 "订单详情页" 中要罗列用户【确认】结算的商品(即用户在购物车页面【勾选】的商品),后端拿到 cartID (多个),在 cart_item 表找到对应的记录,并与 product 表进行关联。
4、在 "商品详情页" 点击 "增加订单" 按钮,后端生成订单信息。
5、支付订单成功,会清空购物车,会将 购物车对应的(多个cartID对应的)记录全部删除。
问题
在重放脚本的时候,将商品加入购物车,会插入往 cart_item 插入新的记录,生成新的自增长主键 cartID。而之后的 "订单详情页","增加订单"操作, "支付"操作,"清空购物车操作" 都【需要】前面生成的 cartID。换言之,就是:前一次请求的结果,作为之后请求的参数。
而 loadrunner 录制的脚本的请求参数都是 "定死的",录制的时候是咋样,生成的脚本就是咋样。录制的时候,支付之后就把购物车给清空了(清除了对应的 cart_item 记录)。脚本中的 cartID ,在清空购物车后就不存在了。脚本重放时,将相同的商品加入购物车,此时往 cart_item 表插入了新的记录,此时对应的 cartID 是新生成的。而拿着旧的 cartID (不存在了,已经被删了),进行之后的 "订单详情页","增加订单"操作, "支付"操作显然会失败。
比较难描述清楚,我已经尽我所能去描述清楚问题根源了。可能对于写过这个项目的同学来说,更能有体会。
假如可以明白上面我所表述的情景,是不是对 loadrunner 中的 "关联" 的概念的理解会更加清晰???
问题解决
核心思想是:从上一次响应的数据中,提取出出对应的参数,作为下一次请求的参数。
回到上面的情况,在购物车的html页面中,有新生成的 cartID。我们只需要拿到响应体,并匹配出来,并作为后续请求的参数即可。
下面介绍相关的 函数:
int web_reg_save_param(const char *ParamName, <list of Attributes>, LAST);
该函数可以在响应数据中匹配出我们需要的值,放在一个请求前面。
o ParamName: 存放得到的动态内容的参数名称
o list of Attributes: 其它属性,包括:Notfound, LB, RB, RelFrameID, Search, ORD, SaveOffset, Convert, SaveLen。属性值不分大小写
o Notfound: 当在返回信息中找不到要找的内容时应该怎么处理
o Notfound=error: 当在返回信息中找不到要找的内容时,发出一个错误讯息。这是缺省值。
o Notfound=warning: 当在返回信息中找不到要找的内容时,只发出警告,脚本也会继续执行下去不会中断。
o LB( Left Boundary ) : 返回信息的左边界字串。该属性必须有,并且区分大小写。
o RB( Right Boundary ): 返回信息的右边界字串。该属性必须有,并且区分大小写。
o RelFrameID: 相对于URL而言,欲查找的网页的Frame。此属性质可以是All或是数字,该属性可有可无。
o Search : 返回信息的查找范围。可以是Headers,Body,Noresource,All(缺省)。该属性质可有可无。
o ORD : 说明第几次出现的左边界子串的匹配项才是需要的内容。该属性可有可无,缺省值是1。如为All,则将所有找到的内容储存起来。
o SaveOffset : 当找到匹配项后,从第几个字元开始存储到参数中。该属性不能为负数,缺省值为0。
o SaveLen :当找到匹配项后,偏移量之后的几个字元存储到参数中。缺省值是-1,表示一直到结尾的整个字串都存入参数。
关于该函数的详细使用,参考以下两篇博客:
https://www.cnblogs.com/feng-1314/p/6733537.html
https://www.cnblogs.com/csdnexpert/archive/2007/12/17/1000008.html
针对上述作业问题的解决,如何使用上述函数进行手动关联。请参看下面代码和注释。
完整代码和注释
Action()
{
int count;
int i;
char param[10][20];
char cartIds[1024];
lr_think_time(9);
// 商品列表页
web_url("prodlist",
"URL=http://localhost:8081/EasyMall/prodlist",
"Resource=0",
"RecContentType=text/html",
"Referer=http://localhost:8081/EasyMall/index",
"Snapshot=t3.inf",
"Mode=HTML",
EXTRARES,
"Url=css/prodList.css", ENDITEM,
"Url=upload/5/2/3/4/7/8/d/c/1838eaa6-6459-420f-b8e2-6ea9f43c4b5e_dfd259ab-bcc7-43f6-a9d5-62872ff5671e.jpg", ENDITEM,
"Url=css/pageHelper.css", ENDITEM,
"Url=js/pageHelper.js", ENDITEM,
"Url=js/jquery-1.4.2.js", ENDITEM,
"Url=upload/5/e/d/5/4/5/e/b/5f0d34dc-157f-49ba-ad39-1b28927ba6ae_1005714.jpg", ENDITEM,
"Url=img/prodlist/search_03.jpg", ENDITEM,
"Url=img/core_bg.png", ENDITEM,
LAST);
lr_start_transaction("add_to_cart_transaction");
// 将商品加入购物车
web_url("addCart",
"URL=http://localhost:8081/EasyMall/cart/addCart?pid=09f47493-214d-44bc-927d-6ce0bf89a057&buyNum=1",
"Resource=0",
"RecContentType=text/html",
"Referer=http://localhost:8081/EasyMall/prodlist",
"Snapshot=t4.inf",
"Mode=HTML",
EXTRARES,
"Url=../css/cart.css", "Referer=http://localhost:8081/EasyMall/cart/showcart", ENDITEM,
LAST);
// 回到商品列表页
web_url("prodlist_2",
"URL=http://localhost:8081/EasyMall/prodlist",
"Resource=0",
"RecContentType=text/html",
"Referer=http://localhost:8081/EasyMall/cart/showcart",
"Snapshot=t5.inf",
"Mode=HTML",
LAST);
// 第2页
web_url("prodlist_3",
"URL=http://localhost:8081/EasyMall/prodlist?page=2",
"Resource=0",
"RecContentType=text/html",
"Referer=http://localhost:8081/EasyMall/prodlist",
"Snapshot=t6.inf",
"Mode=HTML",
EXTRARES,
"Url=upload/7/c/b/f/7/d/2/9/5e229aef-063f-4d0d-91df-2d4aa7167670_6f84843a-1d1e-49c7-b4ce-c035d7790171.jpg", "Referer=http://localhost:8081/EasyMall/prodlist?page=2", ENDITEM,
"Url=upload/4/d/2/a/2/3/1/8/b3c3fc7a-222c-49be-9491-f466553d2284_386718.jpg", "Referer=http://localhost:8081/EasyMall/prodlist?page=2", ENDITEM,
LAST);
web_set_max_html_param_len( "262144"); // 默认最大长度为256
// web_reg_save_param( "ResponseBody" , "LB=" , "RB=" , "Search=Body", LAST);
web_reg_save_param("cart_ids",
"LB=class=\"prodC\" id=\"",
"RB=\"/>",
"ORD=ALL",
"Search=Body",LAST);
//web_save_header( REQUEST , "RequestHeader"); // REQUEST为内置变量,保存请求的头信息,需在发送URL请求前注册使用
//web_save_header( RESPONSE , "ResponseHeader"); // RESPONSE保存响应的头信息
// 将商品加入购物车
web_url("addCart_2",
"URL=http://localhost:8081/EasyMall/cart/addCart?pid=103e5414-0da2-4fba-b92f-0ba876e08939&buyNum=1",
"Resource=0",
"RecContentType=text/html",
"Referer=http://localhost:8081/EasyMall/prodlist?page=2",
"Snapshot=t7.inf",
"Mode=HTML",
LAST);
// ------------------------------------------------------------------------------------
//lr_output_message( "# 请求头信息: \n %s" , lr_eval_string( "{RequestHeader}"));
//lr_output_message( "# 响应头信息: \n %s" , lr_eval_string( "{ResponseHeader}"));
// 为了提取 cartIds
lr_output_message( "# 响应内容体: \n %s" , lr_eval_string( "{cart_ids}"));
count = atoi(lr_eval_string("{cart_ids_count}"));
lr_output_message("购物车中的商品数量:%d", count); // 2
strcpy(cartIds, "");
for(i = 1; i <= count; i++) {
sprintf(param[i], "{cart_ids_%d}", i);//参数名称存到数组中
lr_output_message(lr_eval_string(param[i]));
strcat(cartIds, lr_eval_string(param[i]));
if (i < count) {
strcat(cartIds, ",");
}
}
lr_output_message(cartIds);
lr_save_string(cartIds, "cartIds"); // 保存变量才可以通过{}引用
// ------------------------------------------------------------------------------------
lr_end_transaction("add_to_cart_transaction",LR_AUTO);
lr_think_time(7);
lr_start_transaction("produce_order_transaction");
// debug
// web_save_header( REQUEST , "RequestHeader");
// lr_output_message( "# 请求头信息: \n %s" , lr_eval_string( "{RequestHeader}"));
// 点击生成订单按钮
web_submit_data("order_add",
"Action=http://localhost:8081/EasyMall/order/order_add",
"Method=POST",
"RecContentType=text/html",
"Referer=http://localhost:8081/EasyMall/cart/showcart",
"Snapshot=t8.inf",
"Mode=HTML",
ITEMDATA,
"Name=cartIds", "Value={cartIds}", ENDITEM,
LAST);
// 订单详情页
web_url("order_add_2",
"URL=http://localhost:8081/EasyMall/order/order_add?cartIds={cartIds}",
"Resource=0",
"RecContentType=text/html",
"Referer=http://localhost:8081/EasyMall/cart/showcart",
"Snapshot=t9.inf",
"Mode=HTML",
EXTRARES,
"Url=../css/addOrder.css", "Referer=http://localhost:8081/EasyMall/order/order_add?cartIds={cartIds}", ENDITEM,
LAST);
lr_end_transaction("produce_order_transaction",LR_AUTO);
lr_start_transaction("submit_order_transaction");
// 为了提取订单号
web_reg_save_param("order_id",
"LB=EasyMall/order/payorder?id=",
"RB=src=\"/EasyMall/img/orderList/zx.jpg",
"SaveLen=36",
"Search=Body",LAST);
// 提交订单
web_submit_data("addOrder",
"Action=http://localhost:8081/EasyMall/order/addOrder",
"Method=POST",
"RecContentType=text/html",
"Referer=http://localhost:8081/EasyMall/order/order_add?cartIds={cartIds}",
"Snapshot=t10.inf",
"Mode=HTML",
ITEMDATA,
"Name=receiverinfo", "Value=广东省佛山市南海区狮山镇狮山大学城华南师范大学南海校区(菜鸟驿站)", ENDITEM,
"Name=", "Value=1", ENDITEM,
"Name=cartIds", "Value={cartIds}", ENDITEM,
"Name=", "Value=增加订单", ENDITEM,
EXTRARES,
"Url=../css/orderList.css", "Referer=http://localhost:8081/EasyMall/order/showorder", ENDITEM,
"Url=../img/orderList/zx.jpg", "Referer=http://localhost:8081/EasyMall/order/showorder", ENDITEM,
"Url=../img/orderList/sc.jpg", "Referer=http://localhost:8081/EasyMall/order/showorder", ENDITEM,
LAST);
lr_output_message( "# order_id:%s" , lr_eval_string( "{order_id}"));
lr_end_transaction("submit_order_transaction",LR_AUTO);
lr_start_transaction("pay_transaction");
// 支付订单
web_url("payorder",
"URL=http://localhost:8081/EasyMall/order/payorder?id={order_id}",
"Resource=0",
"RecContentType=text/html",
"Referer=http://localhost:8081/EasyMall/order/showorder",
"Snapshot=t11.inf",
"Mode=HTML",
LAST);
lr_end_transaction("pay_transaction",LR_AUTO);
return 0;
}