2203_75539971 2025-09-10 18:19 采纳率: 0%
浏览 4

Jmeter csv 参数化驱动时 不按文件数据依次读取

Jmeter csv 参数化驱动时 不按文件数据依次读取,真的没辙了 。

 
这是文件数据:
offlineBarcode    sku
6921734968173     10806
416885552    10808
416885553    10809
416885554    10810
416885555    10811
2200097003001    
0000001347    
0000000001    
0000000002    
0000000003    
0000000004    

报错数据1:
{"success":false,"code":"CART200202","msg":"商品不存在416885552","data":{"failureWarePrevent":0,"failureWareList":[{"offlinebarCode":"416885552","skuId":10808,"name":"416885552","failureMsg":"商品416885552不存在","count":1,"uuid":"5807c1e8-8872-4738-a8e6-d885cfdf5a89","failureRealMsg":"商品不存在","shortDisplayMsg":"商品不存在","unitOriginPrice":0}]},"tid":"1a1a2ece2a27ef90"}

报错数据2:
{"success":false,"code":"CART200202","msg":"商品不存在416885552","data":{"failureWarePrevent":0,"failureWareList":[{"offlinebarCode":"416885552","skuId":10809,"name":"416885552","failureMsg":"商品416885552不存在","count":1,"uuid":"5fdc7a35-98fb-49e7-a926-84e71090d255","failureRealMsg":"商品不存在","shortDisplayMsg":"商品不存在","unitOriginPrice":0}]},"tid":"bb49daa73b005b2"}

报错数据3:
{"success":false,"code":"CART200202","msg":"商品不存在416885552","data":{"failureWarePrevent":0,"failureWareList":[{"offlinebarCode":"416885552","skuId":10810,"name":"416885552","failureMsg":"商品416885552不存在","count":1,"uuid":"9b868b0f-acb0-4c02-a572-15fafafe9c43","failureRealMsg":"商品不存在","shortDisplayMsg":"商品不存在","unitOriginPrice":0}]},"tid":"ca7781495d694dfa"}

报错数据4:
{"success":false,"code":"CART200202","msg":"商品不存在416885552","data":{"failureWarePrevent":0,"failureWareList":[{"offlinebarCode":"416885552","skuId":10811,"name":"416885552","failureMsg":"商品416885552不存在","count":1,"uuid":"68ab09b2-8c7e-4ebb-9d3b-0b248574b1fa","failureRealMsg":"商品不存在","shortDisplayMsg":"商品不存在","unitOriginPrice":0}]},"tid":"97183075b72eac7b"}

img

以下是动态参数:


// 2. 创建主请求结构
def requestMap = [
//    baseInfoReq: [supportCalculateMemberPromotion: true],
    cashierId: ${cashierId},
    cashierName: ${cashierName},
    cashierNo: ${cashierNo},
    channel: ${channel},
    deviceCode: ${deviceCode},
    deviceId: ${deviceId},
    newWeighingCountsFlag: 1,
    nonceStr: UUID.randomUUID().toString().replaceAll('-', '').substring(0, 16),
    orgId: ${orgId},
    platform: ${platform},
    posNo: ${posNo},
//    proDeductToken: "",
    qrcode: "",
    storeId: ${orgId},
    tenantId: ${tenantId},
    traceId: UUID.randomUUID().toString().replaceAll('-', ''),
    venderId: ${venderId},
    //version: ${version},
    wareInputList: []
]

// 6. 构建商品列表
def wareItem = new HashMap()


wareItem.changeWeight = 1
log.warn("offlineBarCode:" + "${offlineBarcode}")
wareItem.offlineBarCode = "${offlineBarcode}"

//判断是否不为空 不为空则为国条码需要 saleMode、skuId字段
if (StringUtils.isNotBlank(vars.get("sku"))){
    wareItem.saleMode = 10
    wareItem.skuId = vars.get("sku") as long // 转换为数字类型
}


requestMap.wareInputList.add(wareItem)

//vars.put("offlineBarcode", "")

log.warn("requestMap:" + requestMap)
log.warn("offlineBarcode1:" + "${offlineBarcode}")

Map paramMap = JSON.parseObject(JSON.toJSONString(requestMap), SortedMap.class, Feature.OrderedField);

String sign = "";

boolean isBaseDataType(Class clazz) {
   return (clazz.equals(String.class) || clazz.equals(Long.class) || clazz.equals(Integer.class)
           || clazz.equals(Byte.class) || clazz.equals(Double.class) || clazz.equals(Float.class)
           || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class)
           || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class)
           || clazz.isPrimitive());
}

try {
  StringBuffer sb = new StringBuffer();
  for (String key : paramMap.keySet()) {
      Object value = paramMap.get(key);
      if (value == null) {
          continue;
      }
      String valueStr = null;
      if (!isBaseDataType(value.getClass())) {
          valueStr = JSONObject.toJSONString(value);
      } else {
          valueStr = String.valueOf(value);
      }
      if (StringUtils.isBlank(valueStr)) {
          continue;
      }
      sb.append(key);
      sb.append('=');
      sb.append(valueStr);
      sb.append('&');
  }
  sb.append("key=" + ${dm_key});
  sign = DigestUtils.md5Hex(sb.toString()).toUpperCase();
} catch (Exception e) {
  throw new Exception("签名异常", e);
}


vars.put("sign", sign);
vars.put("param", JSONObject.toJSONString(requestMap));



  • 写回答

4条回答 默认 最新

  • 檀越@新空间 2025-09-10 18:20
    关注

    晚上好🌙🌙🌙
    本答案参考通义千问

    在使用 JMeter 的 CSV 数据文件配置元件(CSV Data Set Config)进行参数化驱动时,如果发现数据不是按顺序读取,可能是由于以下几个原因导致的。下面我将详细分析问题,并提供解决方案代码修改建议


    ✅ 问题分析

    你提供的 CSV 文件内容如下:

    offlineBarcode    sku
    6921734968173     10806
    416885552    10808
    416885553    10809
    416885554    10810
    416885555    10811
    2200097003001    
    0000001347    
    0000000001    
    0000000002    
    0000000003    
    0000000004    
    

    从报错信息来看,sku字段为空,但 JMeter 在读取时却重复使用了同一个 sku(如 10808),这说明 JMeter 并没有按照预期逐行读取 CSV 文件


    🚨 可能的原因

    1. CSV 文件格式问题

      • 检查是否有多余的空格或换行符。
      • 确保每行的字段之间是通过逗号分隔的(而非制表符或其他符号)。
    2. CSV Data Set Config 配置错误

      • 文件名路径是否正确?
      • 变量名是否与脚本中引用的一致(如 offlineBarcodesku)?
      • 文件结束后的处理方式File not foundStop thread)是否设置得当?
    3. 多线程下的并发问题

      • 如果使用了 线程组(Thread Group)且设置了多个线程,每个线程会独立读取 CSV 文件,可能导致重复读取或跳过某些行。
    4. CSV 文件中存在空行或无效行

      • 有些 CSV 文件可能包含空行或注释行,JMeter 默认不会跳过这些行。
    5. JMeter 版本兼容性问题

      • 某些旧版本的 JMeter 可能对 CSV 文件解析有 bug。

    🔧 解决方案

    1. 检查并修正 CSV 文件格式

    • 确保每一行都正确,尤其是最后一几行:

      2200097003001    
      0000001347    
      0000000001    
      0000000002    
      0000000003    
      0000000004    
      
      • 这些行的 sku 字段为空,可能会导致后续逻辑出错。
    • 建议:

      • 删除空行或补充缺失的 sku 值。
      • 使用 Excel 或文本编辑器清理文件。

    2. 正确配置 CSV Data Set Config

    | 参数 | 建议值 | |------|--------| | Filename | yourfile.csv(路径为绝对路径或相对于 JMeter 的 bin 目录) | | Variable Names | offlineBarcode,sku(注意顺序) | | Delimiter | ,(逗号) | | File Encoding | UTF-8(根据文件实际编码) | | Recycle on EOF | False(避免重复读取) | | Stop Thread on EOF | True(到达文件末尾后停止线程) |

    ⚠️ 注意: 如果你在 线程组 中使用了多个线程,应将 “Recycle on EOF” 设置为 True,否则每个线程都会从头开始读取。


    3. 确保变量被正确引用

    在你的 JSR223 PreProcessor 脚本中,你使用了以下语句:

    wareItem.offlineBarCode = "${offlineBarcode}"
    wareItem.skuId = vars.get("sku") as long
    
    • 检查是否成功获取了 offlineBarcodesku 的值
    • 建议添加日志输出,确认变量值是否正确:
    log.warn("offlineBarcode: " + vars.get("offlineBarcode"))
    log.warn("sku: " + vars.get("sku"))
    

    4. 修复脚本中的逻辑问题

    你当前的脚本中可能存在 变量覆盖或未重置的问题。例如:

    //vars.put("offlineBarcode", "")
    
    • 不要在每次循环中清空变量,这会导致下一次读取失败。
    • 建议: 不要手动清除变量,让 JMeter 自动管理。

    5. 修改后的完整脚本示例

    // 2. 创建主请求结构
    def requestMap = [
        cashierId: ${cashierId},
        cashierName: ${cashierName},
        cashierNo: ${cashierNo},
        channel: ${channel},
        deviceCode: ${deviceCode},
        deviceId: ${deviceId},
        newWeighingCountsFlag: 1,
        nonceStr: UUID.randomUUID().toString().replaceAll('-', '').substring(0, 16),
        orgId: ${orgId},
        platform: ${platform},
        posNo: ${posNo},
        qrcode: "",
        storeId: ${orgId},
        tenantId: ${tenantId},
        traceId: UUID.randomUUID().toString().replaceAll('-', ''),
        venderId: ${venderId},
        wareInputList: []
    ]
    
    // 6. 构建商品列表
    def wareItem = new HashMap()
    
    wareItem.changeWeight = 1
    log.warn("offlineBarCode: " + vars.get("offlineBarcode"))
    wareItem.offlineBarCode = vars.get("offlineBarcode")
    
    // 判断是否不为空,不为空则为国条码需要 saleMode、skuId 字段
    if (StringUtils.isNotBlank(vars.get("sku"))) {
        wareItem.saleMode = 10
        wareItem.skuId = vars.get("sku") as Long // 转换为数字类型
    }
    
    requestMap.wareInputList.add(wareItem)
    
    log.warn("requestMap: " + requestMap)
    log.warn("offlineBarcode: " + vars.get("offlineBarcode"))
    
    Map paramMap = JSON.parseObject(JSON.toJSONString(requestMap), SortedMap.class, Feature.OrderedField);
    
    String sign = "";
    
    boolean isBaseDataType(Class clazz) {
        return (clazz.equals(String.class) || clazz.equals(Long.class) || clazz.equals(Integer.class)
                || clazz.equals(Byte.class) || clazz.equals(Double.class) || clazz.equals(Float.class)
                || clazz.equals(Character.class) || clazz.equals(Short.class) || clazz.equals(BigDecimal.class)
                || clazz.equals(BigInteger.class) || clazz.equals(Boolean.class) || clazz.equals(Date.class)
                || clazz.isPrimitive());
    }
    
    try {
        StringBuffer sb = new StringBuffer();
        for (String key : paramMap.keySet()) {
            Object value = paramMap.get(key);
            if (value == null) {
                continue;
            }
            String valueStr = null;
            if (!isBaseDataType(value.getClass())) {
                valueStr = JSONObject.toJSONString(value);
            } else {
                valueStr = String.valueOf(value);
            }
            if (StringUtils.isBlank(valueStr)) {
                continue;
            }
            sb.append(key);
            sb.append('=');
            sb.append(valueStr);
        }
        sign = MD5(sb.toString()); // 假设这里用的是 MD5 加密
        vars.put("sign", sign);
    } catch (Exception e) {
        log.error("Sign generation failed: " + e.getMessage())
    }
    

    ✅ 总结

    | 问题点 | 解决方法 | |--------|----------| | CSV 文件格式错误 | 清理 CSV 文件,确保每行数据正确 | | CSV Data Set Config 配置错误 | 检查 Variable NamesDelimiterRecycle on EOF 等参数 | | 多线程冲突 | 根据需求设置 Recycle on EOFStop Thread on EOF | | 变量未正确引用 | 添加日志验证变量值 | | 脚本中变量覆盖 | 避免手动清空变量,依赖 JMeter 自动管理 |


    📌 最终建议

    • 优先使用 JMeter 内置的 CSV Data Set Config 元件,而不是手动写 JSR223 脚本。
    • 调试时务必开启 JMeter 的日志输出,查看变量是否正常赋值。
    • 测试前先手动运行一次脚本,观察变量值是否符合预期。

    如有更多具体错误信息或脚本内容,欢迎继续提问!

    评论

报告相同问题?

问题事件

  • 创建了问题 9月10日