十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Jmeter接口自动化测试:从CSV读取用例的完整实践

Jmeter接口自动化测试:从CSV读取用例的完整实践 1. 为什么要用 Jmeter 做接口自动化还非得“读用例”做接口自动化测试的朋友基本都经历过这么一段刚接手项目的时候接口数量少直接在 Jmeter 里手写 HTTP 请求一个 Sampler 对应一个用例跑完看一眼结果树好像也挺顺手。等接口数量上到几十个、上百个用例要跟着迭代、回归、换环境跑问题就全冒出来了。我自己最狼狈的一次是把几十个接口的用例全写死在 jmx 脚本里结果开发改了一个字段名我得挨个打开 Sampler 改参数改完还要检查有没有漏改那一刻就下了决心——用例必须从外部文件读取。“Jmeter 接口自动化测试读取用例”这个需求说白了就是把用例数据从脚本里抽出来放到 CSV、Excel 或者数据库里让 Jmeter 通过参数化组件去读。这样做的好处不是“看着规范”而是实打实地解决了几个痛点第一用例和脚本解耦改接口字段不用动 jmx 文件第二同样的脚本可以在测试环境、预发环境、生产环境切换只要换一套用例数据或者改个配置文件第三用例可以交给不懂 Jmeter 的同事维护打开 Excel 就能改第四回归测试的时候往 CSV 里加一行就是加一个用例不需要重新录脚本。这篇文章就是围绕“读取用例”展开的。不管你是刚接触 Jmeter 的小白还是已经写了不少脚本但总觉得维护成本高的测试开发都可以照着下面的思路把用例读取这套东西搭起来。我会从用例文件设计、CSV 参数化的核心配置到登录 token 提取、多线程跑查询接口的完整实操再到一堆我踩过的坑尽量讲透。2. 用例文件设计读取的前提是把“用例”定义清楚很多人一上来就配置 CSV Data Set Config结果文件里随便写了两列数据跑起来发现要么读不到要么读出来的数据压根不是想要的。这里我想先说一个容易被忽略的观点读取这个动作本身很简单难的是用例文件怎么设计决定了你后半段脚本写起来顺不顺手。2.1 CSV 文件接口自动化用例最常用的载体接口用例的载体有很多种CSV、Excel、YAML、JSON、数据库各有各的适用场景。Jmeter 内置支持最好的还是 CSV因为 CSV Data Set Config 是原生组件不需要引入额外的 Jar 包也不需要写 JSR223 脚本来解析 Excel。我在实际项目里见过有人用 Excel 管理用例然后写 BeanShell 或者 Groovy 去读不是说不行而是维护成本和运行稳定性都不如 CSV。Excel 适合给人看CSV 适合给程序读接口自动化用例最终是要被程序消费的所以能用 CSV 就别折腾 Excel。CSV 的格式也需要注意第一行通常是字段名后面每一行是一条用例。Jmeter 默认把第一行当作字段名行通过变量名去引用对应列的值。当然如果关闭“忽略首行”这个选项第一行数据也会被当作用例读进去这种情况一般出现在文件里只有数据、没有表头的场景但我个人不建议这么干因为字段名一旦缺失脚本里全部用变量下标去引用可读性会差很多。2.2 用例字段设计从“能跑”到“好维护”既然用例要外部化字段设计就必须提前规划。我见过一些团队CSV 文件里就两列一列 URL一列参数跑通了就算完事。这种设计其实没有发挥出“用例”的价值。接口自动化用例至少要覆盖这么几个维度用例编号比如 TC001、TC002方便定位失败用例接口路径或者接口名称用于区分不同 Sampler请求方法GET、POST、PUT、DELETE请求参数这是核心参数可以是一个完整的 JSON 字符串也可以是多个参数列预期结果包括预期状态码、预期响应字段的值执行开关有时候需要临时跳过某条用例不用删除用一个 isRun 字段控制。把这些字段落到 CSV 文件里大概是这个样子tc_idapi_pathmethodparamsexpected_codeexpected_msgis_runTC001/api/user/loginPOST{username:test01,password:123456}200success1TC002/api/user/infoGET{userId:1001}200success1有人会问参数是 JSON 格式直接放在 CSV 的一列里Jmeter 读取的时候会不会有问题这里有个很多人不知道的细节CSV 里如果字段值包含了逗号一定要用双引号把整个字段包起来否则 Jmeter 会把逗号当作分隔符切割导致参数被拆成好几列。比如上面例子里的 {username:test01,password:123456} 中间有逗号就必须整体加双引号。我见过不少新手在这里翻车跑出来的请求体缺胳膊少腿还以为是自己 JSON 写错了。2.3 编码与文件路径的坑位提前踩用例文件设计完还有两个前置问题要处理编码和路径。先说编码。Jmeter 读取 CSV 文件的时候默认使用文件的编码格式但 Jmeter 自身界面和很多 Windows 环境下创建的 CSV 文件编码可能是 GBK 或者 ANSI如果文件里有中文参数或者中文预期结果跑起来就会出现乱码。解决办法是统一用 UTF-8 编码保存 CSV 文件或者在 CSV Data Set Config 里的“文件编码”一栏直接填 utf-8。这里有个细节用 Excel 另存为 CSV 的时候Excel 默认会存成 ANSI 编码你以为存的是 CSV其实编码不对建议用 Notepad、VS Code 或者直接命令行转换编码。我自己常用的方式是在 VS Code 里打开 CSV右下角点击编码信息选择“通过编码保存”改成 UTF-8。再说路径。Jmeter 脚本里写文件路径最忌讳的就是写绝对路径比如 C:/Users/xxx/Desktop/testcase.csv。因为脚本一旦拷给别人路径就失效了每次都要改。更优的做法是配合 __P 函数把文件路径定义成 JMeter 属性运行时通过 -J 参数传入或者放到 JMeter 的 bin 目录下用相对路径引用。实际项目里我一般会把用例文件放在 jmx 脚本同级目录下的 data 文件夹然后在 CSV Data Set Config 里写 data/testcase.csv同时配合“与测试计划使用相同目录”这个选项这样整个项目目录拷走脚本和用例文件一起走不会出现路径找不到的问题。3. CSV Data Set ConfigJmeter 里读取用例的核心开关用例文件就位之后接下来就是让 Jmeter 认识它。这一步的核心组件是 CSV Data Set Config。很多教程只告诉你把它拖进来、填个文件名、填个变量名就完事了但实际用起来里面每个配置项都有讲究尤其是“共享模式”和“线程数”的配合直接影响你的用例是“每条线程各读各的”还是“所有线程共享同一份数据”。3.1 CSV Data Set Config 配置项逐条讲先说最基本的几个配置项。文件名就是你的用例文件路径可以配合上面的路径规范填写。文件编码填 utf-8 或者你的实际编码。变量名称这一列很重要多个变量用英文逗号分隔比如 tc_id,api_path,method,params,expected_code,expected_msg,is_run。变量名是你后面在 Sampler 里引用的依据${tc_id}、${params} 这种东西能正常取到值前提就是这个配置项的变量名跟 CSV 的列顺序一一对应。分隔符默认是逗号如果你的 CSV 文件是用 Tab 或者分号分隔的这里要改成对应的符号。有个特殊情况如果你用 Excel 直接编辑 CSVExcel 在一些地区会用分号作为默认分隔符导致 Jmeter 读出来全部是一整列这个坑遇见过一次。遇到这种情况先检查分隔符配置再看文件实际的内容。遇到文件结束符有三个选项Stopthread、循环读取 EOF、Stop test。这个配置决定了用例读完以后线程怎么办。接口自动化回归场景下我一般选“循环读取 EOF”这样用例可以反复跑配合循环次数控制执行多少轮如果你希望跑完所有用例就结束可以选 Stop thread。Stop test 是整份测试计划直接停掉一般用在“用例失败就不继续跑”的联动场景里平时用得不多。3.2 循环次数、线程数和用例条数的关系这个算是读取用例最容易搞混的地方。不少人以为在“线程组”里把线程数设成 N就会执行 N 条用例其实不是。线程数控制的是并发用户数循环次数控制的是每条线程执行多少次而 CSV Data Set Config 的 EOF 选项决定读不到数据之后的行为。三者的乘积才会最终决定你发了多少个请求。举个例子用例文件里一共 5 条数据线程组设线程数为 1、循环次数为 5CSV 每次读取一行第一次循环读第 1 行第二次循环读第 2 行……第五次循环读第 5 行。这是最常规的“单线程逐条跑用例”模式适合接口自动化回归。另一种情况线程数设 5、循环次数设 1同样 5 条用例5 个线程并发启动各自从 CSV 里读一行。这里就牵涉到后面要说的共享模式默认情况下 5 个线程会按顺序从 CSV 文件里拿不同的行第 5 个线程正好拿第 5 行。但如果你把线程数设成 10、循环次数设 1而用例只有 5 条线程 6 到 10 就读不到数据了具体表现是变量取值为空或者读到 EOF 标记。所以想清楚你的场景是关键。并发压测重点在线程数和循环次数的组合自动化回归重点在“用例条数”和“循环次数”的匹配。我在项目里一般会把线程数固定为 1循环次数设成一个比较大的值比如 100然后靠 CSV 的 EOF 选项控制读完就停这样不管用例文件里有多少条数据脚本都不用改。3.3 共享模式真正决定你用例怎么读的参数共享模式是我见过被忽略得最彻底的一个选项但它恰恰决定了多线程下用例读取的行为。Jmeter 提供了四种模式共享模式行为所有线程共享所有线程共同消费一个 CSV 文件指针每条数据只被读一次当前线程组共享同一个线程组里的线程共享文件指针不同线程组各自独立当前线程组内各线程独立每个线程都从第一行开始读各自维护指针线程组间各自独立每条线程都有一个独立的文件指针从头开始读默认情况下是所有线程共享也就是所有线程按顺序领取 CSV 里的行。这种模式在回归测试的时候最合适不会出现两条线程拿到同一条用例的情况。而“当前线程组内各线程独立”就很有意思了每个线程都会从头开始读一遍文件如果你线程数设 5用例 100 条那么每个线程都会跑一遍全部 100 条这就不是“100 条用例”而是“5 个并发角色分别跑 100 条”适合模拟多用户各自完成一套完整流程的场景。举一个实际项目里的例子测试一个登录后查询用户信息的接口我希望 5 个不同用户同时登录、同时查询每个用户只能用自己的 token 查自己的信息。这种场景下我用 5 条用户数据线程组设置 5 个线程共享模式选“所有线程共享”每线程读取不同的用户数据这样每个线程操作自己的账号互不干扰。如果选成“每条线程独立”那 5 个线程都会从第一行读同一个用户第 2 条到尾用户对应的数据就没被用上token 还容易互相覆盖查出来的信息全是一个人的。4. 完整实操登录提取 token5 线程并发跑查询接口前面讲了不少理论这一节来一个能直接照着搭的完整例子。这个例子对应一个很常见的需求Jmeter 模拟登录后同时跑 5 个线程跑查询接口。而且用例数据都是从 CSV 文件里读取的。4.1 接口准备与测试计划结构假设被测系统有两个接口。一个是登录接口POST /api/user/login请求参数是用户名和密码响应里返回一个 token 字段。另一个是用户信息查询接口GET /api/user/info请求头里带上 Authorization: Bearer xxx路径参数或者查询参数里带上 userId。我想要实现的效果是5 个用户同时登录每个用户拿到自己的 token然后同时用这个 token 查询自己的用户信息。测试计划的结构可以这样搭测试计划配置元件CSV Data Set Config读用户账号和用例数据配置元件HTTP Header Manager设置 Content-Type 等公共头线程组线程数5循环次数1登录请求 SamplerJSON Extractor提取 token查询请求 Sampler断言JSON Assertion校验响应里的用户信息查看结果树Summary Report 或者聚合报告这里我把 CSV 配置放在了线程组外面也就是测试计划级别的配置元件。要注意的是CSV Data Set Config 放在不同层级作用域不一样放在线程组外面会被所有线程组共享放在线程组里面则只对当前线程组生效。一般单个线程组场景放哪都行我习惯放在测试计划下统一管理。4.2 CSV 用例文件的字段设计用户账号和查询参数我放在同一个 CSV 里方便维护。文件内容如下username,password,user_id,expected_name zhangsan,abc123,U1001,张三 lisi,abc123,U1002,李四 wangwu,abc123,U1003,王五 zhaoliu,abc123,U1004,赵六 sunqi,abc123,U1005,孙七这里 username、password 是登录接口的入参user_id 是查询接口的参数expected_name 是断言用的预期结果。这样一个文件同时喂给了登录和查询两个接口这就是“读取用例”最大的价值——同一份数据在多处复用不会出现登录用的用户和查询用的用户对不上号的情况。CSV Data Set Config 的配置如下文件名data/user_info.csv文件编码utf-8变量名称username,password,user_id,expected_name分隔符,忽略首行True默认就是 True遇到文件结束符Stop thread共享模式所有线程共享4.3 登录接口取 tokenJSON Extractor 的配置逻辑登录接口的 Sampler 里面请求方法选 POST路径填 /api/user/loginBody Data 我用 JSON 格式。因为参数来自 CSV所以直接用变量引用{ username: ${username}, password: ${password} }这里要注意如果 CSV 里的一列被当成完整 JSON 字符串读取那就不需要手工拼 JSON 结构直接 ${params} 塞进去就行。但如果是分列存储的就得像上面这样手工拼接。登录响应里返回的 token我用 JSON Extractor 提取。添加一个后置处理器配置如下变量名称auth_tokenJSON Path 表达式$.data.token匹配数字1默认值TOKEN_NOT_FOUND这里的逻辑是响应 JSON 里 data 对象下的 token 字段把提取到的值存到变量 auth_token 里。匹配数字填 1表示取第一个匹配结果防止接口返回多个 token 时取到奇怪的值。默认值一定要设置否则提取失败的时候变量是空的后续请求头里就会拼出一个 Authorization: Bearer 这种残缺的请求报错信息还特别难排查。为什么强烈建议用 JSON Extractor 而不是正则提取器之前在热词里也能看到很多人搜“登录 json 提取器”。用一个简单总结就是JSON 响应结构清晰的情况下JSON Path 的可读性和稳定性比正则表达式高太多。正则表达式要写 (?token:)[^] 这种看着头晕的东西还要考虑转义、换行、空格JSON Extractor 只要会写 .data.token 就行。当然如果接口响应不是标准 JSON比如 HTML 页面或者纯文本那就只能用正则提取器但接口自动化场景里 90% 以上都是 JSON优先用 JSON Extractor 没毛病。4.4 查询接口带 token 和参数并发跑起来查询接口的请求头需要带上 Authorization。HTTP Header Manager 里加一个请求头Authorization: Bearer ${auth_token}同时查询参数使用 CSV 里的 user_id在 URL 里拼/api/user/info?userId${user_id}然后线程组设置线程数为 5、循环次数为 1。因为 CSV 文件里正好有 5 行用户数据共享模式是所有线程共享所以线程 1 拿第一行 zhangsan线程 2 拿第二行 lisi以此类推。每个线程登录的时候用的是自己的用户名密码提取到的 token 也是自己的查询的时候 userId 也是自己的这样就天然实现了 5 个用户并发查询自己信息的效果。跑完以后怎么看结果常规操作是加“查看结果树”看请求和响应详情加“汇总报告”看吞吐量、平均响应时间、错误率这些指标。接口自动化场景下我习惯再加一个“断言结果”监听器因为响应是否正确不能只看 HTTP 200。查询接口的响应里会有 name 字段我在查询请求里加一个 JSON Assertion用 $.data.name 和 ${expected_name} 做匹配这样 5 个线程各自校验自己的预期结果只要有一个用户的返回信息和 CSV 里写的不一样断言就会失败测试报告里会明确标出来。断言、token 提取、CSV 参数化这三件套组合起来基本就是一个可复用的接口自动化用例执行框架。在这个基础上后续要加接口只要在 CSV 里加数据、在测试计划里加一个 Sampler或者把接口路径也做成变量就能做到“不打开 jmx 也能加用例”。4.5 测试报告怎么出热词里有人问“jmeter 能出测试报告吗”答案是可以而且不止一种方式。简单的做法是用命令行模式执行脚本Jmeter 会生成一个 HTML 报告jmeter -n -t login_query.jmx -l result.jtl -e -o report_dir-n 表示非 GUI 模式-t 指定脚本-l 输出 JTL 结果文件-e 生成 HTML 报告-o 指定报告输出目录。这个命令我在 CI 环境里用得很多配合 Jenkins 定时触发接口自动化就完全自动跑了。如果你项目里已经在用 InfluxDB 和 Grafana 做监控可以在测试计划里加上 Backend Listener配置 InfluxDB 地址和数据库运行时把指标实时写入 InfluxDBGrafana 出实时监控大屏。这个配置本身不复杂难点主要在于 InfluxDB 的版本和 Jmeter 插件兼容性。我自己踩过的一个坑是 InfluxDB 2.x 的鉴权方式和 1.x 不一样Jmeter 的 Backend Listener 默认走的是 1.x 的写入接口要用 2.x需要额外确认 token 和 bucket 的映射否则数据写不进去。如果不打算上监控大屏直接用 HTML 报告就足够了。5. 常见问题快查与排错心得这一节把我在不同项目里遇到的问题集中整理一下基本覆盖了“Jmeter 接口自动化测试读取用例”这条路上最容易卡住的地方。5.1 CSV 文件读不到、读了不生效表现是脚本跑完了但是请求里的参数是空的或者永远取的是同一个值。排查步骤按下面这个顺序来。先检查文件路径。如果是相对路径确认 jmx 文件当前目录下有没有对应的 data 文件夹如果是绝对路径确认路径里没有中文和空格。这里补一个小技巧在 CSV Data Set Config 里点“浏览”选择文件选择完以后 Jmeter 会自动把路径转成绝对路径如果希望是相对路径再手动改成相对路径的形式。再检查“忽略首行”。如果首行被当成数据读了${username} 取到的值可能是文件里的 username 这个字段名现象就是请求体里 username 被替换成了字符串 username。接着检查线程组设置。如果线程数等于 1、循环次数等于 1那只会读 CSV 的第一行看数据能对上就说明配置没问题对不上就看是不是行数据本身的问题。最后如果所有配置都没问题可以加一个 Debug Sampler 放在请求前面输出当前所有变量值一眼就能看出来 ${username} 到底取到了什么。这个技巧排查变量类问题特别快比盯着查看结果树猜要高效得多。5.2 中文乱码和数据格式问题中文乱码的根源在于文件编码和 Jmeter 读取编码不一致。CSV 文件是 GBK而 CSV Data Set Config 里写的是 UTF-8或者反过来都会乱码。解决办法就是统一。建议所有用例文件统一保存为 UTF-8 编码配置里也统一填 UTF-8。还有一种情况变量引用正常但请求体里中文没了或者变成了奇怪的符号。这时候先看一眼请求体里的编码HTTP 请求 Sampler 的“内容编码”字段如果填的是 UTF-8会强制对请求体做 UTF-8 编码如果填了 GBK就要跟文件编码匹配。不填的话Jmeter 会用默认编码容易出现问题。一般来说请求体里带中文参数就把“内容编码”填成 UTF-8保持和 CSV 文件编码一致。5.3 提取器不生效作用域和变量名问题JSON Extractor 不生效最常见的两个原因。第一个是作用域不对提取器必须放在登录请求的子节点下才能在这个请求完成后执行提取。如果你把提取器放到了线程组下面它会在登录请求执行之前就跑响应还没生成自然提取不到。第二个是变量名写错或者引用时写错比如提取器里变量名称填的是 token请求头里引用成 ${auth_token}那肯定取不到值。我犯过的错是把 ${token} 写到了另外一个线程组里不同线程组的变量默认不互通跨线程组引用的时候需要额外处理这是个冷门坑记住了能省很多排查时间。如果接口响应不是合法 JSONJSON Extractor 提取也会失败。这时候就要看响应头里的 Content-Type 是不是 application/json有的接口返回的是 text/html 但内容确实是 JSONJmeter 的响应体解析默认按 Content-Type 来可能走不到 JSON 解析这条链路。这种情况可以把响应数据保存到文件用肉眼确认一下或者改用正则提取器。5.4 关于 Jmeter 的定位不是所有接口自动化都得用它最后分享一点个人体会。Jmeter 的优势在于协议支持广、并发能力强、和 CI/CD 集成方便特别适合接口回归和性能压测一体化的场景。但如果你追求的是复杂的业务断言、数据驱动测试、接口之间的依赖编排非常复杂Jmeter 的脚本组织能力会显得吃力这时候 Java/Python 的接口自动化框架可能更好热词里也能看到很多人在搜“java 接口自动化测试框架”、“python 做接口自动化测试”。我自己的选型逻辑大致是这样接口数量少、逻辑简单用 Jmeter CSV 足够接口数量中等、有复杂业务流用 Jmeter JSR223 脚本Groovy补足灵活性接口数量和逻辑都很复杂或者需要深度定制报告、和测试平台深度集成的建议直接用代码维护测试框架。工具只是手段不要在工具上钻牛角尖。6. 最后再补充几个自己总结的实操习惯这篇写到这里核心的读取用例内容已经讲完了最后分享几个我长期实践下来觉得很有价值的习惯不算什么高深的东西但确实能减少很多返工。第一个习惯是给每个测试计划都留一个专门放用例文件的目录并在脚本里用相对路径引用同时把“与测试计划使用相同目录”勾上。这样整个测试项目传到任何一台机器上都能跑不用改路径。我见过很多同事把 CSV 文件放在桌面路径写死在 jmx 里等到换了电脑、换了环境跑一次改一次纯粹是给自己挖坑。第二个习惯是给 CSV 文件加上必要的注释列比如“更新人”“更新时间”“备注”。接口自动化用例是要长期维护的资产没有这些信息三个月后你甚至说不清这条用例是给谁用的、当时为什么这么写。加两个字段不影响运行但对维护体验的提升非常明显。第三个习惯是在线程组里加一个 Debug Sampler平时保持禁用状态只有排查问题的时候才启用。因为接口自动化跑完以后排查失败用例最烦的就是变量值不确定Debug Sampler 一开所有变量值立刻可见问题定位效率翻倍。第四个习惯脚本改完以后先在 GUI 模式下用少量数据试跑一遍确认所有请求都符合预期再用命令行模式正式跑全量用例。GUI 模式跑多了电脑会卡但一次性跑少量数据没问题。命令行模式在 CI 里是主力可千万别在 Jenkins 里还开着 GUI 操作。这四个习惯看着细碎但都是我在实际项目里拿时间换来的经验。接口自动化测试这件事难点从来不是“会发一个 HTTP 请求”而是怎么把用例组织得清晰、稳定、可维护。把“读取用例”这一步做好整个框架就立住了一半。后续再往上面加断言、加测试报告、加 CI 集成都是顺理成章的事。
返回列表