在Apache JMeter中,BeanShell是一种强大的预处理器、后处理器和取样器,可以用来执行自定义Java脚本。利用BeanShell,测试人员能够编写复杂的业务逻辑来处理JMeter的请求数据或响应结果,甚至可以根据需要动态地生成和修改测试数据。
利用BeanShell编写自定义脚本处理复杂业务逻辑的基本步骤和示例:
步骤:
添加BeanShell组件:
在JMeter测试计划中,根据需求将BeanShell Sampler、BeanShell PreProcessor 或 BeanShell PostProcessor 添加到线程组下的相应位置。
编写脚本:
打开选定的BeanShell组件,在“Script”区域输入或粘贴你的Java或BeanShell脚本。
可以访问JMeter内置变量(如${variable}),以及通过vars对象访问用户定义的变量,使用props对象访问属性文件中的值。
调用JMeter API方法:
在BeanShell脚本中可以直接调用JMeter提供的API方法,例如设置变量、获取系统信息、处理HTTP请求等。
调试与运行脚本:
如果需要检查脚本的输出或变量状态,可以使用log.info()方法打印日志信息到jmeter.log文件。
运行测试计划,观察控制台输出或监听器的结果,确保脚本按预期工作。
示例脚本: 假设我们有一个场景,需要从上一个HTTP响应中提取某个JSON字段,并将其作为下一个请求的参数传递:
import org.json.JSONObject;
// 获取上一个HTTP响应体内容
String prevResponse = new String(prev.getResponseData());
// 将响应体转换为JSON对象
JSONObject jsonObject = new JSONObject(prevResponse);
// 提取名为"item_id"的字段
String itemId = jsonObject.getString("item_id");
// 设置新的变量用于后续请求
vars.put("next_request_item_id", itemId);
上述脚本首先获取了前一个HTTP响应的内容,然后将其解析为JSON对象,从中提取了"item_id"字段的值,并将其存储在一个新的JMeter变量next_request_item_id中,该变量可以在后续的HTTP请求中引用。
注意:虽然BeanShell支持Java语法,但由于性能原因,从JMeter 3.1版本开始推荐使用JSR223 Sampler并选择Groovy语言进行脚本编写。
电商测试示例
示例1:动态生成订单号
场景:模拟创建新订单时,需要为每个请求生成唯一的订单号。
import java.util.UUID;
// 生成唯一订单号
String orderId = UUID.randomUUID().toString();
// 设置到变量中以便后续请求使用
vars.put("order_id", orderId);
log.info("Generated unique order ID: " + orderId);
示例2:从响应提取并更新购物车商品数量
场景:在获取购物车详情后,根据响应内容动态调整某个商品的数量。
假设响应数据如下(JSON格式):
Json
{
"cart": [
{
"id": "product1",
"quantity": 2,
"name": "Product A"
},
{
"id": "product2",
"quantity": 1,
"name": "Product B"
}
]
}
BeanShell PostProcessor脚本:
import org.json.*;
// 获取响应数据
String response = new String(prev.getResponseData());
// 解析JSON
JSONObject jsonObject = new JSONObject(response);
JSONArray cartItems = jsonObject.getJSONArray("cart");
// 遍历购物车商品,找到指定商品并更新数量
for (int i = 0; i < cartItems.length(); i++) {
JSONObject item = cartItems.getJSONObject(i);
if ("product2".equals(item.getString("id"))) { // 假设我们想增加"Product B"的数量
int currentQuantity = item.getInt("quantity");
item.put("quantity", currentQuantity + 1); // 增加一个单位
vars.put("new_product_b_quantity", Integer.toString(currentQuantity + 1)); // 存储新的数量到变量中
}
}
// 更新后的cartItems可以序列化后设置回请求体,如果下一个请求是更新购物车操作
String updatedCartJson = jsonObject.toString();
vars.put("updated_cart", updatedCartJson);
示例3:登录令牌的管理与重置
场景:用户登录后获得一个有效期较短的令牌(token),在每次发起需授权的请求前都需要检查和更新这个令牌。
String token = vars.get("user_token"); // 获取当前存储的令牌
long currentTime = System.currentTimeMillis() / 1000; // 当前时间戳(秒)
// 检查令牌是否过期(假设令牌过期时间为3600秒)
if (token != null && currentTime - Long.parseLong(vars.get("token_expiration_time")) > 3600) {
// 令牌过期,重新登录获取新令牌
// 这里简略了登录过程,实际上会包含发送登录请求、解析响应并提取新令牌的过程
// ...
// 假设 login 方法返回新的令牌和过期时间
MaptokenInfo = login(username, password);
token = tokenInfo.get("token");
vars.put("user_token", token);
vars.put("token_expiration_time", Long.toString(currentTime + tokenInfo.get("expiration_seconds")));
}
// 将最新的令牌添加到HTTP Header中
sampler.getHeaderManager().add(new Header("Authorization", "Bearer " + token));
示例4:动态价格加载和比较
场景:在商品详情页抓取实际显示的价格,并与数据库中存储的价格进行对比,确保两者一致。
// 从响应中提取实际显示的商品价格
String response = prev.getResponseDataAsString();
int displayedPrice = -1;
Matcher matcher = Pattern.compile("(\\d+(?:\\.\\d+)?)").matcher(response);
if (matcher.find()) {
displayedPrice = Float.parseFloat(matcher.group(1)); // 假设价格是以文本形式展示的
}
// 获取数据库中存储的价格
String storedPriceStr = vars.get("stored_product_price");
double storedPrice = Double.parseDouble(storedPriceStr);
// 比较并记录结果
if (displayedPrice != storedPrice) {
log.error("商品价格不匹配! 显示价格: " + displayedPrice + ", 存储价格: " + storedPrice);
Failure = true; // 设置失败标志,可在后续逻辑中处理错误
} else {
log.info("商品价格校验成功,显示价格与存储价格一致。");
}
示例5:模拟库存同步
场景:当订单创建成功后,根据返回信息更新库存(在测试环境中)。
假设订单创建响应包含商品ID及其数量:
Json
{
"order": {
"id": "1234",
"items": [
{
"productId": "productA",
"quantity": 5
},
{
"productId": "productB",
"quantity": 3
}
]
}
}
BeanShell PostProcessor脚本:
import org.json.*;
String response = prev.getResponseDataAsString();
JSONObject orderJson = new JSONObject(response);
JSONArray items = orderJson.getJSONArray("items");
for (int i = 0; i < items.length(); i++) {
JSONObject item = items.getJSONObject(i);
String productId = item.getString("productId");
int quantity = item.getInt("quantity");
// 假设有一个全局变量或集合用于管理库存,这里仅做演示
int currentStock = Integer.parseInt(vars.get("stock_" + productId));
currentStock -= quantity; // 减去已售出的数量
vars.put("stock_" + productId, Integer.toString(currentStock));
log.info("产品 " + productId + " 库存更新为: " + currentStock);
}
以上案例展示了BeanShell在电商流程中的应用,但请注意,在实际性能测试中应尽量避免使用BeanShell,因其执行效率相对较低。推荐使用JSR223 Sampler配合Groovy语言以获得更好的性能。
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!