当前位置: 首页 > 测试知识 > LoadRunner VuGen C语言脚本开发技巧大全
LoadRunner VuGen C语言脚本开发技巧大全
2026-07-21 作者cwb 浏览次数73

LoadRunner VuGen C 语言脚本开发技巧大全

LoadRunner的VuGen使用标准C语言(或类似 C 的语法)作为脚本语言,并提供了大量 lr_、web_ 等开头的API。掌握C语言基础和 LoadRunner 特有函数的结合技巧是写出稳定、高效、易维护脚本的重点。


一、脚本结构和设计原则

1.三段式结构

vuser_init:只执行一次,用于登录、初始化连接等。

Action:反复执行(根据迭代次数),存放重要业务思路。

vuser_end:只执行一次,用于退出、清理资源。

把初始化思路放在vuser_init,避免每次迭代重复登录;事务尽量放在Action中。


2.用函数封装复用思路


c

// 封装一个登录函数,返回事务是不是成功

int login(const char* user, const char* pwd) {

    int rc = 0;

    lr_start_transaction("login");

    // 提交登录请求...

    if (/* 成功 */) {

        lr_end_transaction("login", LR_PASS);

        rc = 1;

    } else {

        lr_end_transaction("login", LR_FAIL);

    }

    return rc;

}


这样可在 vuser_init 和后续需要重新登录的地方直接调用。


3 使用LR_PARAM宏代替硬编码

c

#define URL "http://www.zmtests.com"

改为:


c

lr_save_string("http://www.zmtests.com", "pUrl");

web_url("step", "URL={pUrl}", LAST);


便于统一管理和参数化。


二、参数化技巧

1.基础参数化

选中值 - 右键 - Replace with a Parameter - 创建参数并指定数据文件。


常见用法:


c

web_submit_data("login",

    "Action=http://www.zmtests.com/login",

    "Method=POST",

    "TargetFrame=",

    "Referer=",

    ITEMDATA,

    "Name=username", "Value={Username}", ENDITEM,

    "Name=password", "Value={Password}", ENDITEM,

    LAST);


2. 动态获取参数值

lr_eval_string("{参数名}") 返回字符串,可用于C变量比较或处理。


c

char *user = lr_eval_string("{Username}");

if (strcmp(user, "admin") == 0) { ... }


注意:lr_eval_string 返回的指针可能在下一次调用后失效,需要及时复制。可用 strcpy 或 lr_save_string 保存。


3.参数更新方法选择

Select Next Row:Sequential / Random / Unique

Update Value On:Each iteration / Each occurrence / Once


场景:模拟不同用户并发时,使用 Unique + Each iteration,并启用When out of values: Abort Vuser可保证数据不重复。如果数据有限,应设置合适的中止方法或循环使用。


4.参数化非字符串类型

整数参数可直接用 {intParam},VuGen 会自动转换为字符串,使用时再转回:


c

int num = atoi(lr_eval_string("{countParam}"));


5.参数文件使用技巧

文件首行作为列名,参数名和列名一致。

支持多个参数共享同一文件多列。

使用 lr_advance_param 可手动推进参数行,实现精细控制:


c

lr_advance_param("MyParam");

三、关联技巧

1.手动关联四步法

录制两份相同业务脚本,对比差别,找出动态值(如 Session ID)。

找到动态值出现的服务器响应,确定左右边界。

在请求之前添加关联函数 web_reg_save_param:


c

web_reg_save_param("sessionID",

    "LB=Set-Cookie: sessionid=",

    "RB=;",

    "Search=Headers",

    LAST);


用 {sessionID} 替换脚本中硬编码的动态值。


2.使用正则表达式关联

边界不规则或需一致复杂方式时,改用 web_reg_save_param_regexp:


c

web_reg_save_param_regexp(

    "ParamName=token",

    "RegExp=token[\"']?\\s*:\\s*[\"']([^\"']+)",

    "Ordinal=1",

    SEARCH_FILTERS,

    "Scope=Body",

    LAST);


可通过 RegExp 设置捕获组。


3.关联多个一致项Array

当响应中有多个相同边界的值时,使用 Ord=All:


c

web_reg_save_param("items",

    "LB=<li class=\"item\">",

    "RB=</li>",

    "Ord=All",

    LAST);


然后用数组接口获取个数和值:


c

int count = atoi(lr_eval_string("{items_count}"));

char itemName[256];

sprintf(itemName, "{items_%d}", i+1);  // 索引从1开始

lr_output_message("Item: %s", lr_eval_string(itemName));


或使用 lr_paramarr_idx、lr_paramarr_len 函数。


4.关联边界转义

特殊字符需转义:如 "LB=name=\"value\""。

如果边界包含换行,可尝试 \r\n,或使用 Search=Body 时开启 Extended 选项。


5.自动关联的使用

录制后VuGen会自动扫描关联建议,可快速建立规则,但必须检查生成的边界是不是鲁棒,避免只对单一响应有效。


四、事务和检查点

1.事必须须成对出现


c

lr_start_transaction("T01_SubmitOrder");

// ... 业务请求 ...

lr_end_transaction("T01_SubmitOrder", LR_AUTO);


严禁事务名称不一致、忘记结束事务或在子函数里开始却不结束。


2.使用检查点判断事务成功


c

web_reg_find("Text=Payment Successful",

    "SaveCount=success_count",

    LAST);


web_submit_data("pay", ...);


if (atoi(lr_eval_string("{success_count}")) > 0)

    lr_end_transaction("T01_Pay", LR_PASS);

else

    lr_end_transaction("T01_Pay", LR_FAIL);


SaveCount 记录了出现次数,即使一次也可用于判断。


3. 事务内不应包含思考时间

如果业务需要,应把 lr_think_time 放到事务外面,或在 Controller 中设置事务不计思考时间。

在VuGen中,可在 Run-time Settings - General - Think Time 设置忽略或按比例回放。


4.图像检查点

c

web_image_check("src=images/logo.gif",

    "Alt=Company Logo",

    LAST);


证实页面完整性。


五、日志和调试

1. lr_output_message 和 lr_log_message

lr_output_message 始终输出到日志和控制台,适合调试。

lr_log_message 发送到 LoadRunner 内部日志,仅在对应日志级别启用时才可见。


c

lr_output_message("当前用户:%s,订单号:%s", lr_eval_string("{user}"), orderNo);


2.设置日志级别

在脚本中动态调整:


c

lr_set_debug_message(LR_MSG_CLASS_EXTENDED_LOG | LR_MSG_CLASS_RESULT_DATA, LR_MSG_ON);

// 调试后关闭

lr_set_debug_message(LR_MSG_CLASS_EXTENDED_LOG, LR_MSG_OFF);


或在 Run-time Settings 的 Log 选项中勾选 Extended log。


3.使用断点和Watch

VuGen 支持设置断点,右键菜单可添加变量到 Watch 窗口,观察参数值变化。

回放时可按 F5 逐步执行。


4.输出服务器返回内容

c

web_reg_save_param("responseBody", "LB=", "RB=", "Search=Body", LAST);

// 请求...

lr_output_message("%s", lr_eval_string("{responseBody}"));


对于调试关联非常有用。


六、C语言常见问题

1.字符串操作安全

永不要使用未初始化的 char 数组作为输出。

使用 snprintf 或保证缓冲区足够大的 sprintf。


c

char temp[512];

snprintf(temp, sizeof(temp), "Order_%s", lr_eval_string("{orderID}"));


LoadRunner 的sprintf在某些版本可能导致栈溢出,安全做法是用 lr_save_string 组合或 snprintf。


2.动态内存管理

VuGen 允许 malloc/free,但必须及时释放,避免在长期运行时内存泄漏。

也可以利用 lr_eval_string 的自动管理,但注意其返回指针的生命周期。

如果使用大量字符串,优先用 LoadRunner 参数系统存储。


3.类型转换

字符串 - 整数:atoi(lr_eval_string("{count}"))

整数 - 字符串:lr_save_int(myNum, "myParam") 或 sprintf

浮点数:可使用 atof,保存浮点参数需用 lr_save_string。


4.处理空参数

c

char *val = lr_eval_string("{optionalParam}");

if (val == NULL || strcmp(val, "") == 0) {

    // 空值处理

}


5.避免全局变量冲突

Action 文件中的全局变量在迭代间会保留,注意重置或用vuser_init初始化。

使用static限制作用域。


6.文件名和途径

文件操作时,相对途径指向脚本目录,可用 lr_get_attrib_string 获取绝对途径。


c

char scriptDir[1024];

lr_get_attrib_string("ScriptDir", scriptDir, sizeof(scriptDir));


七、错误处理和恢复

1.遇到错误继续执行


c

lr_continue_on_error(1);  // 后续步骤即便出错也继续

web_url("step1", ...);

lr_continue_on_error(0);  // 恢复默认


或通过 Run-time Settings - Miscellaneous - Continue on error 全局设置。


2.获取HTTP返回码


c

web_url("step", ...);

int httpCode = web_get_int_property(HTTP_INFO_RETURN_CODE);

if (httpCode != 200) {

    lr_end_transaction("T1", LR_FAIL);

}


3.手动结束脚本


c

lr_exit(LR_EXIT_ABORT, LR_FAIL);

7.4 事务状态赋值技巧

LR_AUTO:根据动作函数的返回状态自动判断。

LR_PASS / LR_FAIL:显式设定。

LR_STOP:非正常停止(如条件不满足时中止事务但不标记失败)。


八、性能优化和运行时设置

1.减少日志输出

在 Controller 运行时,必须关闭 Extended log,只保留标准日志,可大幅降低 I/O 开销。


2.设置合理思考时间

在 Run-time Settings 中可限制为录制值的 50%~150% 随机,或固定值。

不要在事务中包含过大或随机的思考时间,以免影响响应时间统计。


3.关联缓冲区大小

如果返回内容特别大,关联可能截断,需设置:


c

web_set_max_html_param_len("100000");


或使用 web_reg_save_param 的 MaxLength 属性。


4.少用 lr_output_message 在并发场景

高并发时大量打印会拖慢 Vuser,尽量用条件编译或仅在调试时启用。


5.DNS 缓存和连接复用

勾选 Simulate browser cache 和 Use persistent connections 可贴近真实浏览器行为,但需根据测试目的调整。

在 Run-time Settings → Internet Protocol 中设置。


九、高级脚本技术

1.文件读写自定义数据


c

FILE *f = fopen("output.txt", "a");

if (f) {

    fprintf(f, "User %s, Time: %ld\n", lr_eval_string("{user}"), time(NULL));

    fclose(f);

}


注意:多 Vuser 并发写同一文件需自行处理锁(如使用文件队列或 VTS)。


2.调用外部 DLL


c

lr_load_dll("myutils.dll");

// 声明函数

int __declspec(dllimport) Add(int a, int b);

// 调用

int result = Add(3,4);


3.使用Virtual Table Server

可在多 Vuser 间共享数据、同步唯一值,比文件操作更可靠。

函数:vtc_connect、vtc_send_row、vtc_retrieve_row 等。


4.数据库证实


c

lr_db_connect("StepName=DB1",

    "ConnectionString=...",

    "ConnectionName=conn1",

    LAST);

lr_db_executeSQLStatement("StepName=verify",

    "ConnectionName=conn1",

    "SQLStatement=SELECT count(*) FROM orders WHERE ...",

    "DatasetName=ds",

    LAST);


5.加密和编码

Base64 编解码:lr_base64_encode / lr_base64_decode

MD5/SHA:可加载 crypto DLL 或使用 lr_decrypt(用于负载脚本)。

对参数进行简单加密,提升数据安全性。


十、录制和回放设置

1.选择正确的脚本方式

HTML-based script:直观,适合页面元素确定的场景。

URL-based script:录制每个请求,更底层,适合非 HTML 应用或需精确控制资源下载的测试。


2.自动生成脚本后的清理

删除不必要的请求(如第三方统计、广告),保证压测结果准确。

合并无意义的额外 web_url,减少脚本大小。


3.端口映射和代理设置

使用 web_set_proxy 可动态设置代理。

web_set_sockets_option 设置超时等。


4.处理自定义Header


c

web_add_header("Authorization", "Bearer {token}");


十一、集合点和 IP 欺骗

1.集合点使用


c

lr_rendezvous("before_pay");

lr_start_transaction("pay");

// ...


在 Controller 的 Scenario - Rendezvous 中设置激活方法。

注意集合点应放在事务开始之前,否则会影响事务时间统计。


2.IP 欺骗

在 Controller 的 Scenario 中启用 IP Spoofer,并为每个 Vuser 分配不同 IP。

脚本无需改动,但需保证负载生成器支持 IP 别名。


文章标签: 软件测试 测试工具
咨询软件测试