3. 脚本录制与回放:HTTP代理服务器录制、Badboy录制、手动编写脚本基础

脚本获取是性能测试的起点。本章聚焦三种主流脚本构建方式:HTTP代理服务器录制、Badboy工具录制以及纯手动编写。每种方式适用场景不同,掌握其原理与操作要点,能让你在面对各类被测系统时快速产出高质量脚本。

3.1 三种脚本构建方式对比

方式 适用场景 优点 缺点 学习成本
HTTP代理服务器录制 Web/移动端HTTP(S)请求 零编码、快速捕获请求序列 易混入无关请求、需手动过滤 低
Badboy录制 带AJAX/复杂交互的Web应用 可视化操作、自动关联动态参数 工具停止维护、仅限Windows 中
手动编写脚本 API接口、非HTTP协议、参数化复杂场景 完全可控、无冗余、可复用性强 需熟悉JMeter元件与协议细节 高
选型建议: 首次接触新系统时,优先使用HTTP代理服务器录制快速生成骨架脚本;对于含大量异步请求的富客户端应用,可尝试Badboy录制;当需要精确控制请求参数、断言逻辑或处理非HTTP协议时,必须采用手动编写方式。

3.2 HTTP代理服务器录制

JMeter内置的HTTP代理服务器是最常用的录制方式。其原理是:JMeter在本地启动一个代理端口,浏览器或移动端将流量指向该代理,JMeter拦截并记录所有HTTP(S)请求,自动生成对应的Sampler。

3.2.1 配置步骤

  1. 添加HTTP代理服务器: 右键“测试计划” → 添加 → 非测试元件 → HTTP代理服务器。
  2. 设置端口: 默认8888,确保未被占用。
  3. 目标控制器: 选择录制结果存放的线程组。
  4. 分组策略: 建议选择“在每个线程组的新控制器中分组”,便于后续按页面/功能模块整理。
  5. 请求过滤: 在“包含模式”/“排除模式”中添加正则,过滤掉静态资源(.css、.js、.png、.ico等)和第三方统计请求。
  6. 启动代理: 点击“启动”按钮,JMeter会弹出证书提示(录制HTTPS时需要安装根证书)。
  7. 配置浏览器代理: 将浏览器HTTP/HTTPS代理指向127.0.0.1:8888。
  8. 执行操作: 在浏览器中完成业务操作,JMeter实时捕获请求。
  9. 停止录制: 点击“停止”按钮,移除浏览器代理设置。
避坑要点: 录制HTTPS站点时,必须先在浏览器中导入JMeter生成的ApacheJMeterTemporaryRootCA.crt证书,否则请求会失败。录制完成后务必删除该证书,避免安全风险。

3.2.2 录制后脚本清洗

原始录制脚本通常包含大量冗余请求,必须进行清洗才能用于压测:

  • 删除静态资源: 图片、CSS、JS、字体文件等非业务核心请求。
  • 合并请求: 将连续的同域名请求合并为一次,减少网络往返。
  • 参数化: 将登录态、订单号、用户ID等动态值替换为变量。
  • 添加断言: 为关键请求添加响应断言,确保业务成功。
  • 添加思考时间: 使用Uniform Random Timer模拟用户操作间隔。

3.3 Badboy录制

Badboy是一款独立的Web测试录制工具,支持录制、回放和导出为JMeter脚本。虽然已停止更新,但在处理AJAX、动态页面元素方面仍有独特优势。

3.3.1 录制流程

  1. 打开Badboy,在地址栏输入被测系统URL。
  2. 点击红色“录制”按钮,开始操作。
  3. Badboy自动记录所有请求、Cookie、Session信息。
  4. 录制完成后,点击“文件” → “导出” → “导出为JMeter脚本”。
  5. 在JMeter中打开导出的.jmx文件,进行参数化和断言调整。
Badboy vs HTTP代理服务器: Badboy能自动识别页面中的动态参数(如ViewState、EventValidation),并生成对应的正则表达式提取器,减少手动关联工作量。但Badboy不支持HTTP/2协议,且对现代SPA应用(如Vue、React)的录制效果较差。

3.4 手动编写脚本基础

手动编写脚本是性能测试工程师的核心能力。它不依赖录制工具,完全通过JMeter元件构建请求,适合接口测试、非HTTP协议场景以及需要精细控制的压测脚本。

3.4.1 手动编写核心元件

元件类型 作用 常用实现
线程组 定义虚拟用户数、Ramp-Up时间、循环次数 线程组、setUp线程组、tearDown线程组
Sampler 发送具体请求 HTTP请求、JDBC请求、Java请求、SOAP/XML-RPC请求
配置元件 管理请求默认值、参数化数据 HTTP请求默认值、CSV数据文件设置、用户定义的变量
前置处理器 在请求前执行逻辑 用户参数、JDBC前置处理器、JSR223前置处理器
后置处理器 从响应中提取数据 正则表达式提取器、JSON提取器、边界提取器
断言 验证响应是否符合预期 响应断言、JSON断言、大小断言
监听器 查看和保存测试结果 查看结果树、聚合报告、图形结果

3.4.2 手动编写示例:登录接口

以下是一个手动编写的HTTP登录请求脚本片段:

<!-- 线程组配置 -->
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="登录压测" enabled="true">
  <stringProp name="ThreadGroup.num_threads">10</stringProp>
  <stringProp name="ThreadGroup.ramp_time">5</stringProp>
  <boolProp name="ThreadGroup.same_user_on_next_iteration">false</boolProp>
</ThreadGroup>

<!-- CSV数据文件配置 -->
<CSVDataSet guiclass="TestBeanGUI" testclass="CSVDataSet" testname="用户数据" enabled="true">
  <stringProp name="filename">users.csv</stringProp>
  <stringProp name="variableNames">username,password</stringProp>
  <boolProp name="quotedData">false</boolProp>
  <boolProp name="recycle">true</boolProp>
  <boolProp name="stopThread">false</boolProp>
</CSVDataSet>

<!-- HTTP请求 -->
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="登录请求" enabled="true">
  <stringProp name="HTTPSampler.domain">api.example.com</stringProp>
  <stringProp name="HTTPSampler.port">443</stringProp>
  <stringProp name="HTTPSampler.protocol">https</stringProp>
  <stringProp name="HTTPSampler.path">/api/v1/login</stringProp>
  <stringProp name="HTTPSampler.method">POST</stringProp>
  <boolProp name="HTTPSampler.postBodyRaw">true</boolProp>
  <stringProp name="HTTPSampler.arguments">
    {"username":"${username}","password":"${password}"}
  </stringProp>
</HTTPSamplerProxy>

<!-- JSON提取器 -->
<JSONPostProcessor guiclass="JSONPostProcessorGui" testclass="JSONPostProcessor" testname="提取" enabled="true">
  <stringProp name="JSONPostProcessor.referenceNames"></stringProp>
  <stringProp name="JSONPostProcessor.jsonPathExprs">$.data.</stringProp>
  <stringProp name="JSONPostProcessor.match_numbers">0</stringProp>
</JSONPostProcessor>

<!-- 响应断言 -->
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="登录成功断言" enabled="true">
  <stringProp name="Assertion.test_field">ASSERTION_TEXT_RESPONSE</stringProp>
  <stringProp name="Assertion.test_string">"code":200</stringProp>
  <boolProp name="Assertion.assume_success">false</boolProp>
</ResponseAssertion>

3.5 脚本录制与回放流程总览

下图展示了从录制/编写到回放验证的完整工作流:

脚本录制与回放工作流 HTTP代理服务器录制 浏览器 → JMeter代理 → 自动生成 Badboy录制 可视化操作 → 导出.jmx 手动编写脚本 线程组 + Sampler + 断言 脚本清洗与参数化 删除冗余 / 参数化 / 添加断言 单用户回放验证 查看结果树 / 断言通过 / 无报错 验证通过? (业务/响应/关联) 否 是 进入容量压测

3.6 三种方式的最佳实践

实战建议:
  • 混合使用: 先用HTTP代理录制获取请求骨架,再手动调整参数化、关联和断言逻辑。
  • 录制前规划: 明确要录制的业务路径,避免录制无关操作增加清洗工作量。
  • 手动编写优先: 对于核心接口(登录、下单、支付),建议手动编写脚本,确保完全可控。
  • 版本控制: 所有.jmx脚本纳入Git管理,录制脚本和手动脚本分开存放。

3.7 常见问题与排查

问题现象 可能原因 解决方案
录制时浏览器无法打开页面 代理端口被占用或证书未安装 更换端口;重新安装JMeter根证书
录制结果为空 浏览器未配置代理或过滤规则过严 检查代理设置;放宽包含模式
Badboy导出脚本乱码 编码不匹配 在Badboy中设置UTF-8编码后重新导出
手动脚本请求失败 缺少Header或Cookie 添加HTTP信息头管理器;检查Cookie管理器配置
回放时断言失败 动态参数未关联或响应格式变化 使用后置处理器提取动态值;更新断言表达式