API性能测试JSON和XML是主要的响应数据格式。LoadRunner提供了多种强大且灵活的方法来处理这两种格式的数据。
1. JSON响应数据处理
LoadRunner处理JSON主要有两种方法:使用web_reg_save_param_ex配合"Json=All"边界(简单情形)和使用lr_json_string_to_value等原生JSON函数(复杂、推荐)。
方法一:使用边界函数
适用于提取简单的、位于固定结构中的值。
cpp
// 在返回JSON的请求前,注册一个关联函数
web_reg_save_param_ex(
"ParamName=json_response",
"LB=",
"RB=",
"SEARCH_FILTERS=Json=All", // 重点:声明响应是JSON
LAST);
web_custom_request("get_user",
"URL=http://api.zmtests.com/user/123",
"Method=GET",
LAST);
// 此时,`json_response`参数包含了整个JSON响应体。
// 你可以使用类似XML的方法,通过`lr_eval_string_ext`和字符串查找来分析,但这很笨拙。
// 对于嵌套的JSON,更推荐下面的方法二。
方法二:使用原生JSON函数(LoadRunner 11.52+,推荐)
处理JSON最强大、最专业的方式。
cpp
#include "lrw_custom_body.h"
#include "lrw_json.h" // 保证包含JSON头文件
Action()
{
const char *json_string = NULL;
JSON *json_obj = NULL;
char *extracted_value = NULL;
web_reg_save_param_ex("ParamName=json_resp", "LB=", "RB=", "SEARCH_FILTERS=Json=All", LAST);
web_custom_request("get_user", "URL=...", LAST);
// 步骤1: 将参数化的JSON字符串转换为JSON对象
json_string = lr_eval_string("{json_resp}");
json_obj = lr_json_string_to_value(json_string, NULL, NULL, NULL);
// 步骤2: 使用JSON Path表达式提取值
// 假设响应体为: {"data": {"user": {"id": 1001, "name": "john_doe"}, "level": "VIP"}}
extracted_value = lr_json_get_string(json_obj, "$.data.user.id", NULL); // 提取 id
lr_save_string(extracted_value, "extracted_user_id");
lr_log_message("提取到的用户ID: %s", extracted_value);
extracted_value = lr_json_get_string(json_obj, "$.data.user.name", NULL); // 提取 name
lr_save_string(extracted_value, "extracted_user_name");
// 步骤3: 处理JSON数组
// 假设响应体为: {"items": [{"sku": "A001"}, {"sku": "A002"}]}
JSON *items_array = lr_json_get_array(json_obj, "$.items", NULL);
int array_size = lr_json_get_array_size(items_array);
for (int i = 0; i < array_size; i++) {
JSON *item_obj = lr_json_get_array_item(items_array, i);
extracted_value = lr_json_get_string(item_obj, "$.sku", NULL);
lr_log_message("商品 %d 的SKU: %s", i+1, extracted_value);
// 可以将SKU保存到数组中,供后续参数化使用
sprintf(param_name, "SKU_%d", i+1);
lr_save_string(extracted_value, param_name);
}
// 步骤4: 释放JSON对象内存(重要!)
lr_json_free_value(json_obj);
// 步骤5: 使用提取的值发起下一个请求
web_custom_request("update_user",
"URL=http://api.zmtests.com/user/{extracted_user_id}/update",
"Body={\"newName\": \"{extracted_user_name}_updated\"}",
LAST);
return 0;
}

文章来源:卓码软件测评
精彩推荐:点击蓝字即可
▲软件负载测试 ▲API自动化测试 ▲软件测试 ▲第三方软件测试 ▲软件性能测试 ▲软件测试机构
2. XML响应数据处理
处理XML主要使用web_reg_save_param_ex配合"Xml=All",并结合XPath或左右边界。
方法一:使用XPath(最精确、推荐)
cpp
// 在返回XML的请求前,注册关联函数
web_reg_save_param_ex(
"ParamName=user_id_list", // 存储多个一致值的数组
"LB=",
"RB=",
"SEARCH_FILTERS=Xml=All, XPath=/Response/Users/User/@id", // 重点:使用XPath
// XPath 表达式提取所有User节点的id属性
LAST);
web_custom_request("get_users_xml",
"URL=http://api.zmtests.com/users.xml",
LAST);
// 提取成功后,可以使用来下方式访问:
int count = atoi(lr_eval_string("{user_id_list_count}")); // 获取一致项总数
for (int i = 1; i <= count; i++) {
sprintf(param_name, "{user_id_list_%d}", i); // 创建参数名,如 user_id_list_1
lr_log_message("用户ID %d: %s", i, lr_eval_string(param_name));
}
方法二:使用左右边界(适用于简单或固定位置)
cpp
web_reg_save_param_ex(
"ParamName=single_user_name",
"LB=<Name>",
"RB=</Name>",
"Ordinal=1", // 提取第一个一致项
"SEARCH_FILTERS=Xml=All", // 声明响应是XML,分析器会更严格
LAST);
3. 注意事项
关联位置:关联函数(web_reg_save_param_ex)必须放置在目的请求之前。
动态边界:如果左右边界本身是动态的,可以结合已关联的参数来构造新的边界字符串,有时需要转义。
JSON/XML声明:在使用web_reg_save_param_ex时,必须根据响应格式正确使用"Json=All"或"Xml=All"。这会让VuGen使用相应的分析器,而不是简单的文本一致,从而更可靠。
错误处理:在使用lr_json_get_string等函数后,应检查返回值是不是为NULL,以防止后续脚本因空指针而崩溃。
性能考量:复杂的XPath或JSON Path表达式以及大型文档的分析会消耗一定的CPU资源。在负载测试中,如果每个虚拟用户都频繁进行复杂分析,可能会影响测试机本身的性能。对于在负载中只需提取一次的值(如会话ID),应放在vuser_init中处理。
内容检查:除了关联,还可以使用web_reg_find配合"Search=Json"或"Search=Xml"来证明响应体中是不是包含某个特定的JSON键值对或XML节点。
通过熟练掌握以上针对JSON和XML的关联和处理技巧,能够高效地应对绝大多数根据RESTful API或SOAP Web服务的应用系统的性能测试脚本开发工作。