ARTICLE DETAIL

资讯详情

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

Jmeter接口测试实战:从环境搭建到性能压测全攻略

Jmeter接口测试实战:从环境搭建到性能压测全攻略 做测试这些年被问到最多的问题就是接口测试到底怎么测工具选什么Jmeter和Postman、Apifox到底有什么区别其实在我来看Jmeter是接口测试这条路上绝对绕不开的一个工具——它既能做单接口调试又能做全链路接口回归同一套脚本稍微改改就能直接转成性能压测。这篇我不打算写成官方文档式教程就按实际干活的经验把Jmeter接口测试从环境准备、测试计划搭建、断言提取、加密签名一直到压测实战和问题排查完完整整过一遍。适合刚入行的功能测试准备转接口测试也适合已经会用一点Jmeter但总觉得没摸透、遇到问题不知道从哪下手的同学。1. 环境准备与核心概念先把地基打牢1.1 安装配置不踩坑JDK版本、环境变量与启动配置Jmeter本身是用Java写的桌面应用装它之前必须先有JDK这是新手最容易翻车的地方。先说版本匹配Jmeter 5.x系列建议用JDK 8或JDK 11JDK 8最稳我自己长期用的是JDK 8。个别新版本要求JDK 17但日常接口测试没必要追新稳定压倒一切。安装JDK后配置环境变量Windows机器上主要做两件事新建JAVA_HOME指向JDK安装目录再把%JAVA_HOME%\bin追加到Path变量。配置完打开命令行敲java -version能正常输出版本号就说明环境没问题。Jmeter本体去官网下载选择Binary版本Windows直接解压就行完全绿色免安装。进入解压目录的bin文件夹Windows双击jmeter.bat启动Mac/Linux运行jmeter.sh。第一次启动如果弹出安全提示或者界面卡顿不用慌多半是内存配置的问题。打开jmeter.bat文件找到一段关于HEAP的配置默认是-Xms1g -Xmx1g -Xn512m这套参数在脚本复杂、线程多的时候容易爆内存。我一般改成-Xms2g -Xmx4g -Xmn1g前提是你的机器内存够用压测机本身至少要留出4G以上的空闲内存给Jmeter不然压测过程中Jmeter自己先崩了就谈不上测试系统了。还有个细节是界面语言。老版本的Jmeter默认英文界面很多新手一看满屏英文直接就劝退了。其实Jmeter官方一直有中文语言包只是默认没启用。在jmeter.properties文件里找到languageen改成languagezh_CN重启之后就是完整的中文界面。这一步做完大部分基础操作就能上手了学习门槛一下低了不少。1.2 用点外卖理解HTTP接口测试一次请求到底发生了什么接口测试说穿了就是验证“客户端发给服务端的请求”和“服务端返回的响应”是否符合预期。HTTP请求可以拿点外卖来打比方URL是店铺地址告诉服务端你要访问哪个资源请求方法是点餐动作GET是看菜单不点单POST是下单PUT是改单DELETE是退单请求头是口味备注比如“不要香菜”对应Content-Type、Authorization请求体是订单明细告诉服务端你具体要什么数据响应状态码是商家反馈200表示接单成功404表示你要的菜不存在500表示后厨着火出故障了。接口测试要验证的远不止状态码。我平时会把验证点分成三层第一层看响应码确认网络层和路由层没毛病第二层看响应体里的业务字段比如code是否为0、message是否正确、关键数据字段是否有值第三层看业务逻辑比如登录接口返回的token能不能直接用于后续带鉴权的请求下单接口提交的优惠券金额是否和库里的实际金额一致。这三个层次从浅到深越是靠后的越能发现真正影响用户的问题。1.3 工具选型Jmeter、Postman、Apifox怎么选很多新手纠结工具选型其实不用纠结三个工具各有各的主场。Postman强在单接口调试编辑请求、看响应都非常顺手适合开发自测和临时调试。Apifox更适合团队协作接口文档、Mock、调试集成在一个平台里国内团队用得很多热词里总有人搜“apifox接口测试教程”可见普及度很高。但如果你要做性能压测或者要写一套能长期回归的接口脚本Jmeter几乎是不二之选。工具核心能力最适合的场景局限性Jmeter接口测试性能压测一体化脚本可复用接口回归、压测、全链路验证界面相对朴素学习曲线略陡Postman简单快速的单接口调试开发自测、快速手工验证压测能力弱脚本工程化能力有限Apifox接口文档Mock调试协作前后端联调、团队接口管理压测能力不强接口量级大时性能有限我的建议是日常调试用Postman或Apifox正式做接口回归和压测必须落到Jmeter。更关键的是Jmeter的jmx脚本是纯文本格式可以放到Git仓库里做版本管理团队成员改动后提交记录一清二楚这一点在真正的测试工程化里非常重要。2. 从零搭建第一个接口测试计划动手跑通请求2.1 测试计划的核心结构线程组、请求、监听器和公共配置打开Jmeter后左侧导航栏默认有一个测试计划右键测试计划可以添加线程组。刚开始接触Jmeter会觉得层级很乱实际上理解透了一张图就够测试计划是根节点下面是线程组线程组里放各种采样器也就是具体的HTTP请求请求下面可以挂断言、提取器这些子节点最外层再挂监听器来查看结果。线程组是Jmeter执行任务的最小单元“线程数”可以理解为同时有多少用户来访问“Ramp-Up时间”表示这些线程在多长时间内启动完“循环次数”表示每个线程跑几遍脚本。举个例子线程数100、Ramp-Up 10、循环次数5含义是10秒内启动100个线程然后每个线程把请求循环执行5次总的请求数就是100*5500次。这里有个新手特别容易弄错的点线程数不等于并发数。只有当Ramp-Up时间远小于单次请求响应时间时线程池才可能真正“叠”在一起形成并发。实际压测时线程数和Ramp-Up都要根据接口的响应耗时去估算不能拍脑袋。线程组下面紧接着要配置“HTTP请求默认值”。这个东西的价值在于把公共的协议、域名、端口、编码统一配置一次后续所有HTTP请求都会自动继承。比如被测环境是http://test.api.example.com:8080在请求默认值里写清楚之后所有请求只需要写接口路径就行不用每个请求都重复填一长串URL。这个配置在新手阶段看着不起眼一旦脚本里面有几十个接口就知道它多重要了——改一次环境地址整个脚本就切换完毕比手动一个个改快到不知哪里去了。2.2 手把手写一个POST请求JSON请求体与响应格式化就以最常见的登录接口为例走一遍完整流程。先在测试计划下添加一个线程组线程数先填1方便调试。在请求默认值里填好服务器域名和端口比如http://test.api.example.com。然后在线程组下添加“HTTP请求”采样器在请求面板中设置请求方法POST路径/api/login请求体内容Body Data填{username:${user},password:${pwd}}其中${user}和${pwd}是变量后面通过参数化来赋值这里有一个关键操作POST请求带JSON体必须添加一个HTTP信息头管理器设置Content-Type: application/json。否则服务端收到的请求体会被识别成普通表单JSON解析直接报错。这个坑十个人里有八个踩过一定要记住。请求建好后添加监听器“查看结果树”。运行一次点击请求右侧能看到请求头和响应体。响应如果是JSON格式在查看结果树的“JSON”页签里可以直接树状展开不用肉眼去看一长串压缩后的字符串这就是热词里常说的“请求体响应体JSON格式化”。调试阶段我习惯开着查看结果树但到压测阶段一定关掉它——这个监听器会把所有响应数据都存到内存里线程一多Jmeter自身内存直接被打爆压测结果全废。2.3 用CSV做数据驱动一份文件跑一百条测试用例接口测试不可能一条数据测到底登录接口至少得覆盖正常用户、密码错误用户、被锁定用户、空参数用户。手工一条条改请求体太蠢了正确做法是数据驱动用CSV文件把数据准备好Jmeter自动读取并代入请求。实操步骤先建一个login_data.csv文件第一行是变量名第二行开始是数据username,password,expect zhangsan,123456,success lisi,errorpass,fail wangle,123456,locked然后在线程组下添加“CSV数据文件设置”文件名填CSV的绝对路径变量名称填username,password,expect分隔符填逗号文件编码必须选UTF-8。这里特别注意不要用Windows自带的记事本另存为CSV记事本容易存成ANSI编码中文直接乱码。建议用VS Code或Notepad存成UTF-8无BOM格式。配置完成后之前HTTP请求里的${user}、${pwd}会自动从CSV的每一行中取值循环多少次就自动执行多少行数据。配合断言就可以实现“一份数据文件批量验证多条用例”的效果。热词里有人搜“jmeter上传文件”CSV同样可以驱动文件上传的路径字段把不同测试文件路径放在CSV里用${filepath}引用非常适合批量上传场景。3. 进阶玩法断言、动态提取与加密签名3.1 断言怎么写才算有效别让脚本“假绿”很多新手加了断言但和没加一样因为他只断言了状态码200。状态码200只能说明服务端收到了请求并处理了处理结果是对是错完全不知道。真正有效的断言至少要覆盖业务结果。Jmeter里常用的断言有三种。第一种是“响应断言”可以断言响应文本中包含某个字符串适合快速校验接口返回的提示语或关键字段。比如登录接口成功时返回“登录成功”失败时返回“用户名或密码错误”就在响应断言里加一个“成功”作为包含模式。第二种是“JSON断言”通过JSONPath表达式直接判断字段值比如$.code等于0这种方式更精确不会因为提示语文案变动而误报。第三种是对响应状态码断言只能作为基础校验不能单独依赖。我的习惯是每个接口至少两层断言一层断言状态码200保证链路通一层用JSON断言校验核心业务字段保证业务逻辑对。比如用户查询接口除了断言$.code 0我还会断言$.data.userName不为空——用户查出来了且用户名叫出来了这个接口才算真的成功。单纯断言“请求成功”反而最没价值。3.2 从响应里动态取数据正则提取身份证生日接口测试里经常遇到接口A的响应数据是接口B的入参最常见的就是登录后拿到token后续所有请求都要在Header里带Authorization: Bearer ${token}。这个场景就要用到“正则表达式提取器”或“JSON提取器”。热词里有个很具体的“jmeter提取身份证的生日”我拿这个场景展开讲。假设注册接口的响应体如下其中idCard字段返回了一个身份证号{ code: 0, data: { idCard: 110101199001011234 } }现在要在下一个接口里用生日19900101作为查询条件。思路分两步第一步用正则提取器把完整的身份证号提取出来第二步用后置处理器从身份证号里截取生日部分。第一步在注册请求下添加“正则表达式提取器”配置如下引用名称idCard正则表达式idCard:(\d{17}[\dXx])模板$1$匹配数字1这里解释一下正则的含义\d{17}匹配17位数字[\dXx]匹配最后一位可以是数字或X身份证校验位可能出现X。外面套上括号表示提取分组$1$取第一个分组。特别注意不要写成.*这种贪婪匹配否则遇到响应里多个身份证号时容易提取到错误的数据。第二步在同一个请求下添加“JSR223后置处理器”语言选Groovy脚本写String idCard vars.get(idCard); String birthday idCard.substring(6, 14); vars.put(birthday, birthday); log.info(extracted birthday: birthday);身份证号第7到14位是出生日期所以在Java字符串里substring(6, 14)正好取出8位生日。之后在后续请求里直接用${birthday}引用就行。这里有个新手常犯的错在纯正则里直接用(\d{4})(\d{2})(\d{2})去提取生日这样做不是不行而是容易误匹配响应体里其他8位数字比如手机号前8位导致数据错乱。先提取身份证号再用程序截取每一步都在掌控之中排查问题也容易。3.3 接口要MD5签名怎么办从函数到Groovy脚本很多企业接口出于安全考虑会在请求参数里加一个sign字段规则一般是“参数值拼接盐值”后做MD5。Jmeter里实现签名有两个常用方案。方案一用内置函数适合规则简单的场景。比如规则是md5(用户名密码盐值)直接写${__digest(MD5,${username}${password}mysalt,,,)}函数的原始值会在发送请求前先计算成MD5串。如果还需要时间戳配合时间函数一起用${__digest(MD5,${username}${__time(/1000,)}mysalt,,,)}注意${__time(/1000,)}生成的是10位秒级时间戳不带参数默认是毫秒级13位数字很多接口签名约定用的是秒级这个细节要和接口文档对齐。方案二用JSR223预处理器加Groovy脚本适合签名规则复杂的场景比如参数要按字母排序、要拼接多层盐值等。以规则“按key升序拼接参数值后再拼盐值做MD5”为例import org.apache.commons.codec.digest.DigestUtils; String username vars.get(username); String timestamp String.valueOf(System.currentTimeMillis() / 1000L); String secretKey your_secret_key_here; String raw timestamp timestamp username username secretKey; String sign DigestUtils.md5Hex(raw); vars.put(timestamp, timestamp); vars.put(sign, sign);这段脚本放在HTTP请求的“JSR223预处理器”里会在请求发送前执行计算好的签名和时间戳会写入变量请求体里直接用${sign}、${timestamp}引用。Groovy脚本的好处是灵活但千万别在预处理器里做耗时操作否则每个请求都会拖慢压测节奏。如果只是几个变量的拼接计算影响可以忽略。另外很多公司会约定MD5输出必须是小写md5Hex方法输出的就是小写如果接口约定大写用md5Hex(...).toUpperCase()转一下就行。3.4 上传文件接口multipart/form-data的正确姿势热词“jmeter上传文件”也算是个高频场景。Jmeter里实现文件上传其实不难难点在于很多新手不知道“参数名”和“请求体格式”的关系。以用户头像上传接口为例先在HTTP请求面板里勾选“Use multipart/form-data”然后在请求参数区添加参数参数名称avatarFile这个名称必须和接口文档定义的字段名完全一致参数值点击右侧“浏览”按钮选择本地文件参数类型选择“文件”同时如果接口还需要另外传一个userId字段在同一个表单里再添加一行参数类型选“文本”值填用户ID。这样Jmeter发送请求时会自动生成multipart格式文件内容和普通文本字段会在同一个请求体里一起提交。这里有个经常踩的坑上传请求失败时先看响应体里的错误信息如果是“参数缺失”或“字段不存在”多半是参数名称和对端定义不一致。如果报“文件格式不支持”要检查你选的文件类型是否符合接口限制。如果报“Content-Type不对”要检查是否为每个文件字段都正确设置了MIME类型。另一个坑是文件路径不要带中文某些服务端对中文文件名或中文路径处理不友好直接用英文路径最省心。4. 从接口测试走向性能压测实测几个关键问题4.1 从接口脚本到压测脚本只用改三个地方接口测试脚本调试通过之后转成压测脚本非常快我一般只做三件事。第一把线程组的线程数调大按估算的并发数设置第二把查看结果树、聚合报告这种重监听器删掉或注释掉换成简单的“汇总报告”或直接生成HTML报告第三把循环次数设成合理值或“永远”配合压测时长来控制请求总量。压测执行时一般不用GUI界面GUI跑压测既耗资源又不稳定。正确姿势是命令行执行jmeter -n -t test_plan.jmx -l result.jtl -e -o report/参数含义-n表示非GUI模式运行-t指定jmx脚本路径-l指定结果文件jtl格式-e表示执行后生成HTML报告-o指定报告输出目录。命令跑完后report目录里会生成一份完整的HTML性能报告打开index.html就能看到平均响应时间、TPS、错误率、90%响应时间等关键指标。从聚合报告或HTML报告里看性能我重点看五个数据指标含义关注点Samples总请求数确认压测时长内请求量是否足够Average平均响应时间整体耗时水平90% Line90%请求在多少毫秒内完成长尾场景更关注这个Throughput每秒处理请求数TPS系统吞吐能力核心指标Error %错误率超过0.1%就要优先排查特别提醒一句平均响应时间会被极端值拉偏90% Line甚至99% Line才是更真实的用户体验。如果90% Line远高于平均值说明有一小撮请求特别慢可能是连接池不足或GC抖动排查时要结合服务端监控一起看。4.2 压测时并发数怎么定估算方法与阶梯加压“jmeter压测怎么确认系统的并发数”是热词说明大家卡在同一个地方。并发数不是一个凭空拍的值它反映的是业务真实场景中“同一时刻正在处理的请求数”。最实用的估算方法是基于业务量。假设系统日活用户10万人每个用户平均每天操作20次高峰集中在4个小时内集中系数假设为3。计算过程如下日总请求量10万20200万次高峰4小时14400秒平均每秒请求数200万/14400≈139次考虑集中系数3高峰期每秒约417次请求。如果平均响应时间是0.5秒那么真正同时在处理的请求也就是并发约为4170.5≈208。这个值就是压测时的目标并发量参考。当然估算只是起点最终要拿数据说话。我通常用阶梯加压的方式找到系统拐点先设线程数20跑1分钟观察TPS和响应时间再改50跑1分钟再改100再改200每档记录TPS、响应时间、错误率。当TPS不再随并发数上升、反而开始下降或持平同时响应时间明显变长这个点就是系统的容量拐点。在做并发评估报告时把每个阶梯的数据都附上比只给一个最终并发数有说服力得多。4.3 HTTPS压测与WebDriver场景录制脚本时注意的坑热词里有人搜“jmeter录制https脚本”还有一个“jmeter安全证书”。实际工作中Jmeter录制HTTPS请求前必须先处理证书问题。Jmeter录制时本质上是做了中间人代理——它会生成一个CA证书浏览器或被测客户端必须信任这个证书否则HTTPS握手直接失败。处理办法是启动Jmeter的录制代理在Jmeter的bin目录下会生成一个ApacheJMeterTemporaryRootCA.crt证书文件把这个证书导入到被测系统浏览器的“受信任的根证书颁发机构”里录制时再设置HTTP代理为本地端口HTTPS请求就能正常记录了。这里务必注意证书有效期过期后要重新生成并重新导入否则会报SSL握手错误。还有一个热词“jmeter使用jpgc - webdriver sampler”这是JMeter插件里的WebDriver Sampler可以启动真实浏览器执行UI操作适合需要完整渲染页面的场景比如人脸识别这类强依赖界面逻辑的系统。但WebDriver Sampler有几个明显短板每个线程都会启动一个浏览器实例内存消耗巨大浏览器启动和渲染耗时严重拉低TPS稳定性也受浏览器版本影响。我的建议是优先做接口级压测覆盖核心链路和容量评估WebDriver只用来做少量端到端验证。如果系统必须做UI级压测把浏览器实例数量控制在个位数更多依赖并发脚本而非浏览器数量来模拟压力。5. 常见问题与面试高频题从报错到话术5.1 让人头大的经典报错排查速查接口测试跑多了总会遇到各种奇奇怪怪的问题。我把踩过的坑按“现象-原因-解法”整理成一张速查表遇到问题直接对号入座。现象大概率原因解决方案响应体中文乱码Jmeter读取响应数据时用了默认ISO-8859-1编码在jmeter.properties里设置sampleresult.default.encodingUTF-8请求发送成功但服务端报参数缺失忘记设置Content-Type: application/json添加HTTP信息头管理器显式设置Content-Type断言一直失败但界面看着数据是对的断言内容与响应体实际字符有细微差异比如空格、Unicode转义、大小写在查看结果树里仔细核对响应原文复制原文字符串作为断言内容CSV参数化后变量没生效CSV路径写错或编码不是UTF-8变量名与请求中引用名不一致改用绝对路径用UTF-8无BOM格式核对变量名压测时Jmeter内存溢出线程数太大且保留了查看结果树等监听器关闭重监听器调大Jmeter的HEAP内存参数NoHttpResponseExceptionHTTP连接被服务端或中间件主动断开客户端还复用旧连接调整Jmeter的HTTP请求实现或者尝试用HTTPClient4并减少Keep-Alive连接复用时间ResultCollector.action_if_file_exists弹窗问题命令行执行脚本时结果文件已存在Jmeter默认会弹窗询问覆盖还是追加执行命令时加参数-Jresultcollector.action_if_file_exists00覆盖、1追加、2重命名或每次指定新文件名上传文件的请求体不对文件被当成文本参数传了或者multipart字段名和接口对不上确认文件参数类型为“文件”字段名与接口文档一致文件路径用英文HTTPS录制时请求失败证书未正确导入被测端或证书过期重新生成Jmeter根证书并导入检查被测端信任列表线程组设置了1000但实际TPS上不去可能不是Jmeter问题而是被测系统、数据库、网络或压测机本身成为瓶颈逐层排查先看压测机CPU再看服务端CPU、内存、磁盘、网络逐层定位这里重点说下“ResultCollector.action_if_file_exists”弹窗问题因为它确实冷门但一旦遇到就很烦。这个问题一般出现在非GUI模式执行脚本、且命令里的结果文件名已经存在时。Jmeter默认行为是弹出对话框让你选择覆盖、追加还是重命名这在命令行环境下就会卡住不动。处理办法就是在命令中显式指定参数告诉它遇到已存在文件直接覆盖整个压测才能自动跑完。5.2 接口测试一般怎么测工作流与面试话术热词有“接口测试一般怎么测”“接口测试面试题”说明不少人在准备面试或者刚接触接口测试时对整体流程没概念。我按自己的工作经验拆一下接口测试落到流程上就五步第一步搞清需求与接口文档。没有接口文档就先抓包找开发确认字段含义和业务规则。第二步设计接口测试用例。用例不是简单测个正常流程就完了必须覆盖正常场景、异常参数、边界值、鉴权失效、依赖关系等。第三步准备测试数据与环境包括被测系统地址、测试账号、数据库初始数据、第三方依赖的mock数据。第四步在Jmeter里实现用例用CSV做数据驱动用断言校验业务结果用提取器串联接口依赖。第五步执行并生成报告把结果归档为回归做准备。面试时问到“怎么设计接口测试用例”我习惯用“先纵向再横向”的思路回答纵向是指对单个接口做充分覆盖包括正常、非法、边界、缺失、超长、特殊字符参数横向是指做接口关联场景测试把业务主链路串起来跑验证数据流转是否正确。问到“接口依赖怎么处理”回答“用正则提取器或JSON提取器把前一个接口的关键数据保存为变量后续请求引用变量”就对了。问到“压测怎么判断系统瓶颈”回答“看TPS是否随并发线性增长如果TPS不再增长而响应时间飙升再用监控工具逐层排查CPU、内存、IO、连接池是否达到极限”也基本能过关。还有一个高频问题“token失效怎么办”。接口用例跑久了token过期很常见处理思路是在线程组里加一个全局的登录请求用后置提取器取出token存成JMeter属性然后勾选线程组配置里的“在每次迭代中运行该登录请求”或者通过脚本判断是否过期。简单粗暴的用法是设置登录请求只在测试计划启动时执行一次后续请求统一通过${__P(token,)}引用稳妥一点的做法是加一个脚本判断如果某请求返回401就重新执行登录并更新token属性。做接口测试时间久了我最大的体会是工具操作本身只占工作量的三成剩下的七成在于你怎么理解业务、怎么设计用例、怎么把脚本做得能稳定回归。Jmeter的优势恰恰在于它给了你一个非常明确的链路——写请求、做断言、提取数据、参数化、跑压测——每一个环节都能落成具体实践。很多时候接口测试的价值不是“测出了多少bug”而是通过持续回归保证核心链路不挂在性能测试时又能提供一份可复现的基线数据。我的建议是别贪多求全先从登录、查询这类最核心的接口开始把断言、提取、参数化这三个基本操作练熟脚本慢慢丰富起来整套能力自然就长在身上了。
返回列表