智能衣橱项目性能测试学习笔记
智能衣橱项目性能测试学习笔记
1. 课程概述
1.1. 课程目的
本课程的目的,是让学生结合当前“智能衣橱”项目,掌握 整个 Web 网站性能测试的基本流程,能够把性能测试从“只会压接口”提升到“会分析业务、会设计场景、会执行测试、会做结果分析”。
通过本课程,学生应当能够:
- 理解性能测试在 Web 项目中的作用和基本概念。
- 能根据业务需求采集结果,分析并计算目标并发数。
- 能使用 JMeter 完成一个基础性能测试脚本开发。
- 能围绕真实业务流程设计测试场景,而不是只测单个接口。
- 能掌握基准测试、配置测试、负载测试、稳定性测试的基本方法。
- 能对测试结果进行初步分析,并指出可能的性能瓶颈位置。
1.2. 内容要求
结合本次学习任务,本课程内容要求如下:
前言
1.2.1 需求分析要求
需要学会:
- 根据业务访问特点进行需求采集。
- 明确测试对象、测试目标、测试指标。
- 根据峰值用户数、停留时间等信息,计算并发数。
1.2.2 脚本开发要求
需要学会:
- 使用 JMeter 搭建基础测试计划。
- 完成登录、用户首页、用户衣物列表这一条完整业务链路脚本。
- 掌握参数化、关联、断言、Header 配置等基础能力。
1.2.3 场景设计要求
需要学会:
- 从“单接口”过渡到“页面链路”设计。
- 能根据业务比例设计简单的混合场景。
- 能完成基准测试、负载测试、稳定性测试的基础场景实现。
1.2.4 测试监控和执行要求
需要学会:
- 按顺序执行基准测试、配置测试、负载测试、稳定性测试。
- 在执行过程中观察响应时间、吞吐量、错误率。
- 结合服务器资源、数据库表现,对结果进行初步分析。
1.2.5 本次的落地要求
由于课时有限,本次教学不追求把所有模块全部压完,而是要求学生先完成:
- 一个完整入门流程:
登录 -> 用户首页 -> 用户衣物列表 - 在此基础上理解如何扩展到:
- 管理员用户列表
- 衣柜列表
- 知识库阅读全文
- 订单下单
- 图片上传
- AI 对话
感谢李瑾同学提供的案例,在资料包中有jar包和对应的sql文件(源代码这里就不提供了)
也可以使用其他项目学习本节内容,不限于本项目
2. 本项目先看什么
前言
运行指令:java -jar smart-wardrobe.jar

访问:localhost:8080

2.1 项目技术结构
前端
- Vue 3
- Vite
- Axios
后端
- Spring Boot
- MyBatis-Plus
- MySQL
数据库文件
smart_wardrobe.sql
2.2 主要业务模块
这个系统不是单一功能,而是一个完整网站,主要包括:
- 登录注册
- 用户首页
- 用户资料
- 衣柜管理
- 衣物管理
- 穿搭推荐
- 知识库
- 穿搭服务与订单
- 图片上传
- AI 穿搭顾问
2.3 为什么性能测试不能只测 1 个接口
因为用户点开一个页面时,往往不是只调用 1 个接口。
例如用户首页,前端真实链路会调用:
/api/users/profile# 用户资料/api/clothes# 衣物列表/api/wardrobes# 衣柜列表/api/users/stats/home# 统计数据
所以性能测试要学会从:
- “单接口测试”
过渡到:
- “页面链路测试” 👈
3. 入门流程:
用户登录 -> 用户首页 -> 用户衣物列表
3.1. 第一步:需求分析
前言
1 先明确本次要测什么
我们先不测全站,只测一个最基础、最真实的用户使用路径:
登录
-> 进入用户首页
-> 查看我的衣物列表
2 对应接口
1. 登录
POST /api/auth/login
2. 用户首页
GET /api/users/profileGET /api/clothesGET /api/wardrobesGET /api/users/stats/home
3. 用户衣物列表
GET /api/clothes
3 为什么先选这个流程
因为这个流程已经具备性能测试里最基础的几个对象:
- 登录接口
- 普通查询接口
- 多接口组合事务
- 分页列表
如果这个流程学会了,后面再扩展到订单、上传、AI 就容易很多。
3.2 第二步:并发数计算
前言
1 性能测试里“并发数”是什么
并发数不是总用户数,而是:
- 同一时间正在使用系统的人数
2 简化计算公式
常用公式:
并发用户数 = 峰值时间内访问用户数 × 平均停留时间 / 峰值时间长度3 示例
假设:
- 峰值 10 分钟内有 60 个用户访问系统
- 每个用户平均停留 5 分钟
则:
并发数 = 60 × 5 / 10 = 30所以本次入门案例,我们先取:
- 目标并发数:30
说明:
- 30 并发适合演示
- 后续正式扩展可以上升到 50 并发,100 并发,200 并发,甚至 500 并发
3.3 第三步:测试计划
前言
1 本次入门测试目标
验证在 30 并发 下:
- 用户是否能正常登录
- 用户首页是否能正常加载
- 用户衣物列表是否响应稳定
- 错误率是否可接受
2 本次入门测试范围
只覆盖:
- 登录
- 用户首页
- 用户衣物列表
暂不纳入:
- 图片上传
- AI 对话
- 管理员增删改
3 本次目标指标
简单指标:
| 指标 | 目标 |
|---|---|
| 登录接口 P95 | 小于 1000 ms |
| 用户首页事务 P95 | 小于 2000 ms |
| 衣物列表接口 P95 | 小于 1000 ms |
| 错误率 | 小于 1% |
P90: 90% 的请求在 1000ms 内完成
P95: 95% 的请求在 1000ms 内完成
P99: 99% 的请求在 1000ms 内完成
3.4 第四步:测试数据制作
前言
1 先看当前数据库数据量
当前 smart_wardrobe.sql 里大约只有:
- 用户:11 条
- 衣柜:11 条
- 衣物:35 条
这只能做:
- 功能验证
- 脚本联调
不能直接拿来做正式性能测试。
2 为什么数据量太小不行
因为数据量太小时:
- 查询几乎都很快
- 分页压力不明显
- 数据库瓶颈看不出来
最少要准备哪些测试数据 👈

- 用户账号数据

执行testev.sql的内容,你会发现,数据库中多了很多数据
- 如果要压衣物查询
数据库里必须保证这些用户:
- 有自己的衣柜
- 有自己的衣物

否则脚本虽然跑通,但业务不真实。
3.5 第五步:脚本开发
前言
这里建议使用 JMeter。
1 先准备 1 份账号数据
先在 JMeter 所在目录,或者当前项目目录下,准备一个 testuserdata.csv 文件。
文件内容不要写表头,直接写账号数据,例如:
test001,123456,USER
test002,123456,USER
test003,123456,USER这 3 列分别对应:
- 用户名
username - 密码
password - 角色
role
2 先把测试计划骨架搭出来
建议按下面顺序点击菜单,先把空架子搭好,再填内容。
1. 新建线程组
测试计划(Test Plan) -> 右键 -> 添加(Add) -> 线程(Threads) -> 线程组(Thread Group)线程组名称改成:UserFlow
2. 添加用户定义变量
测试计划(Test Plan) -> 右键 -> 添加(Add) -> 配置元件(Config Element) -> 用户定义的变量(User Defined Variables)可以增加这几个变量:
| 变量名 | 值 |
|---|---|
| protocol | http |
| host | localhost |
| port | 8080 |

3. 添加 HTTP 请求默认值
测试计划(Test Plan) -> 右键 -> 添加(Add) -> 配置元件(Config Element) -> HTTP 请求默认值(HTTP Request Defaults)在界面中填写:
- 协议:
${protocol} - 服务器名称或 IP:
${host} - 端口号:
${port}

4. 添加公共请求头
测试计划(Test Plan) -> 右键 -> 添加(Add) -> 配置元件(Config Element) -> HTTP 信息头管理器(HTTP Header Manager)名称改成:公共请求头
添加两行:
Content-Type -> application/json
Accept -> application/json
5. 添加 CSV 数据集配置
测试计划(Test Plan) -> 右键 -> 添加(Add) -> 配置元件(Config Element) -> CSV Data Set Config在界面中填写:
- Filename:
testuserdata.csv - File Encoding:
UTF-8 - Variable Names:
username,password,role - Ignore first line:
False - Delimiter:
, - Recycle on EOF:
True - Stop thread on EOF:
False

如果有标题列,则 需要忽略首行 True
6. 添加仅一次控制器
线程组 UserFlow -> 右键 -> 添加(Add) -> 逻辑控制器(Logic Controller) -> 仅一次控制器(Once Only Controller)这个控制器下面只放登录请求,表示每个线程只登录一次。
7. 添加两个事务控制器
线程组 UserFlow -> 右键 -> 添加(Add) -> 逻辑控制器(Logic Controller) -> 事务控制器(Transaction Controller)连续添加两个,并分别改名:
用户首页用户衣物列表
事务控制器建议勾选:
Generate parent sample
这样后面看报告时,可以直接看到“整个页面事务”的耗时。

8. 添加调试用监听器
线程组 UserFlow -> 右键 -> 添加(Add) -> 监听器(Listener) -> 察看结果树(View Results Tree)
线程组 UserFlow -> 右键 -> 添加(Add) -> 监听器(Listener) -> 汇总报告(Summary Report)刚开始联调时保留 察看结果树,正式压测前再关掉或删除。

3 最终推荐结构
Test Plan - 测试计划
├─ User Defined Variables - 用户定义的变量
├─ HTTP Request Defaults - HTTP 请求默认值
├─ HTTP Header Manager - 公共请求头
├─ CSV Data Set Config - CSV 数据集配置
└─ Thread Group - UserFlow
├─ Once Only Controller - 仅一次控制器
│ └─ HTTP Request - 登录
│ ├─ JSON Extractor - 提取 token、userId
│ ├─ Response Assertion - 状态码断言
│ └─ Response Assertion - 业务码断言
├─ Transaction Controller - 用户首页
│ ├─ HTTP Header Manager - 已登录请求头
│ ├─ 获取用户资料
│ ├─ 获取衣物
│ ├─ 获取衣柜
│ └─ 获取首页统计
├─ Transaction Controller - 用户衣物列表
│ ├─ HTTP Header Manager - 已登录请求头
│ └─ 获取衣物列表
├─ View Results Tree - 察看结果树
└─ Summary Report - 汇总报告4 第一步开发登录请求
1. 添加登录请求
仅一次控制器(Once Only Controller) -> 右键 -> 添加(Add) -> 取样器(Sampler) -> HTTP请求(HTTP Request)名称改成:登录
2. 填写登录请求基本信息
在 登录 请求里填写:
- Method:
POST - Path:
/api/auth/login
3. 填写请求体
切换到 Body Data 页签,粘贴:
{
"username": "${username}",
"password": "${password}",
"role": "${role}"
}
4. 提取登录后的 token 和 userId
登录返回JSON格式:
{
"code": 1,
"msg": "success",
"data": {
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIyMSIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNzc4MDc4Mzk5LCJleHAiOjE3NzgxNjQ3OTl9.-lwiON8QIyFXMlO9w2qjrhuQI5dsj4D1qLv_X3jEm_Q",
"userId": 21,
"username": "perf_user_020",
"nickname": "测试用户020",
"role": "user",
"avatar": null
}
}操作:👇
登录 -> 右键 -> 添加(Add) -> 后置处理器(Post Processors) -> JSON Extractor名称改成:提取token和userId
填写如下:
- Names of created variables:
token;userId - JSON Path Expressions:
$.data.token;$.data.userId - Match No.:
1;1 - Default Values:
NOT_FOUND;NOT_FOUND

这一步做完后,后续请求里就可以直接使用:
${token}${userId}
5. 给登录请求加断言
先加响应码断言:
登录 -> 右键 -> 添加(Add) -> 断言(Assertions) -> 响应断言(Response Assertion)填写方式:
- Apply to:
Main sample only - Response Field to Test:
Response Code - Pattern Matching Rules:
Equals - Patterns to Test:
200

再加业务码断言:
登录 -> 右键 -> 添加(Add) -> 断言(Assertions) -> 响应断言(Response Assertion)填写方式:
- Apply to:
Main sample only - Response Field to Test:
Text Response - Pattern Matching Rules:
Contains - Patterns to Test:
"code":1
如果接口返回的 JSON 中有空格,也可以写成:
"code" : 1
5 第二步开发“用户首页”事务
1. 先给事务控制器加登录后请求头
事务控制器 用户首页 -> 右键 -> 添加(Add) -> 配置元件(Config Element) -> HTTP 信息头管理器(HTTP Header Manager)名称改成:已登录请求头
添加一行:
Authorization -> Bearer ${token}
这样该事务控制器下的所有请求都会自动带上 token。
2. 添加“获取用户资料”请求
事务控制器 用户首页 -> 右键 -> 添加(Add) -> 取样器(Sampler) -> HTTP请求(HTTP Request)名称改成:获取用户资料
填写:
- Method:
GET - Path:
/api/users/profile
切换到 Parameters 页签,增加:
userId -> ${userId}
3. 添加“获取衣物”请求
事务控制器 用户首页 -> 右键 -> 添加(Add) -> 取样器(Sampler) -> HTTP请求(HTTP Request)名称改成:获取衣物
填写:
- Method:
GET - Path:
/api/clothes
参数填写:
page -> 1
pageSize -> 100
userId -> ${userId}
4. 添加“获取衣柜”请求
事务控制器 用户首页 -> 右键 -> 添加(Add) -> 取样器(Sampler) -> HTTP请求(HTTP Request)名称改成:获取衣柜
填写:
- Method:
GET - Path:
/api/wardrobes
参数填写:
page -> 1
pageSize -> 100
userId -> ${userId}
5. 添加“获取首页统计”请求
事务控制器 用户首页 -> 右键 -> 添加(Add) -> 取样器(Sampler) -> HTTP请求(HTTP Request)名称改成:获取首页统计
填写:
- Method:
GET - Path:
/api/users/stats/home
参数填写:
userId -> ${userId}
6. 给这 4 个请求复制断言
每个请求都建议加两种断言:
Response Code = 200- 响应体中包含
"code":1
操作方式和前面的登录请求完全一样,可以按下面顺序做:
获取用户资料 -> 右键 -> 添加 -> 断言 -> 响应断言
获取衣物 -> 右键 -> 添加 -> 断言 -> 响应断言
获取衣柜 -> 右键 -> 添加 -> 断言 -> 响应断言
获取首页统计 -> 右键 -> 添加 -> 断言 -> 响应断言如果嫌一个个加太慢,也可以先在一个请求上配好,再复制粘贴到其他请求下。

6 第三步开发“用户衣物列表”事务
1. 先加登录后请求头
事务控制器 用户衣物列表 -> 右键 -> 添加(Add) -> 配置元件(Config Element) -> HTTP 信息头管理器(HTTP Header Manager)添加:
Authorization -> Bearer ${token}
2. 添加“获取衣物列表”请求
事务控制器 用户衣物列表 -> 右键 -> 添加(Add) -> 取样器(Sampler) -> HTTP请求(HTTP Request)名称改成:获取衣物列表
填写:
- Method:
GET - Path:
/api/clothes
切换到 Parameters 页签,填写:
page -> 1
pageSize -> 20
userId -> ${userId}
name ->
category ->
color ->
season ->
status ->
3. 给“获取衣物列表”加断言
获取衣物列表 -> 右键 -> 添加(Add) -> 断言(Assertions) -> 响应断言(Response Assertion)同样加两类:
Response Code = 200- 响应体包含
"code":1

7 最后做一次联调验证
1. 先设置线程组参数
点击 线程组 UserFlow,先填写一个最简单的调试配置:
- Number of Threads:
1 - Ramp-Up Period:
1 - Loop Count:
1
2. 运行脚本
工具栏绿色开始按钮 -> 点击运行
3. 查看结果
线程组 UserFlow -> 察看结果树(View Results Tree) -> 依次点开每个请求
重点看 4 件事:
- 登录响应里有没有成功返回
token - 后续接口请求头里有没有
Authorization: Bearer xxx - 后续接口参数里有没有正确带上
${userId}对应的真实值 - 每个请求是否都返回
200,且响应体里有"code":1
4. 如果后续请求失败,优先排查这 3 个地方
JSON Extractor的路径是否写对了,例如$.data.tokenAuthorization是否少了前缀Bearerusers.csv里的账号是否真实存在,且密码正确
到这里,一个最基础的业务链路脚本就完成了:
登录 -> 用户首页 -> 用户衣物列表后面只需要在这个结构上继续扩展,就可以慢慢加上更多真实业务流程。
3.6 第六步:场景设计
这里讲解基本的性能测试场景设计,包括基准测试、负载测试、稳定性测试。
前言
1 先明确场景设计的原则
场景设计不是去改接口,而是复用 3.5 里已经搭好的业务脚本,只调整:
- 线程数
- Ramp-Up
- 持续时间
也就是说,三个场景跑的其实是同一条链路:
登录 -> 用户首页 -> 用户衣物列表只是压力大小不同。
2 先把监听器整理好
联调时可以保留 察看结果树,但正式压测时建议只保留 汇总报告,避免监听器本身影响结果。
1. 保留汇总报告
线程组 UserFlow -> 右键 -> 添加(Add) -> 监听器(Listener) -> 汇总报告(Summary Report)如果前面已经加过,就不用重复加。
2. 联调时保留察看结果树
线程组 UserFlow -> 右键 -> 添加(Add) -> 监听器(Listener) -> 察看结果树(View Results Tree)正式压测前建议把它禁用:
察看结果树(View Results Tree) -> 右键 -> 禁用(Disable)
3 基准测试怎么配
基准测试的目的,是先看单用户下系统到底有多快。
1. 点击线程组
线程组 UserFlow -> 单击右侧会显示线程组参数。
2. 填写基础参数
把线程组参数改成:
- Number of Threads(线程数):
1 - Ramp-Up Period(启动时间):
1 - Loop Count(循环次数):
Forever或一个足够大的值
如果你的 JMeter 版本里有 Forever 复选框,就勾上它;如果没有,就把循环次数设成足够大。
3. 打开调度器
向下找到 Scheduler,勾选它,然后填写:
- Duration(持续时间):
300
也就是 5 分钟。
4. 保存为基准测试文件
文件(File) -> 另存为(Save As)建议保存为:baseline.jmx
4 负载测试怎么配
负载测试的目的,是验证在目标并发 30 下,流程是否稳定。
1. 重新打开脚本
文件(File) -> 打开(Open)选择刚才保存的脚本文件,或者直接在当前文件里继续修改。
2. 修改线程组参数
把线程组改成:
- Number of Threads(线程数):
30 - Ramp-Up Period(启动时间):
180 - Loop Count(循环次数):
Forever或一个足够大的值
3. 设置持续时间
勾选 Scheduler,然后填写:
- Duration(持续时间):
600
也就是 10 分钟。
4. 保存为负载测试文件
文件(File) -> 另存为(Save As)建议保存为:load.jmx
5 稳定性测试怎么配
稳定性测试的目的,是看系统在一段时间内会不会越来越慢,或者错误越来越多。
1. 修改线程组参数
把线程组改成:
- Number of Threads(线程数):
20 - Ramp-Up Period(启动时间):
120 - Loop Count(循环次数):
Forever或一个足够大的值
2. 设置持续时间
勾选 Scheduler,然后填写:
- Duration(持续时间):
1800
也就是 30 分钟。
3. 保存为稳定性测试文件
文件(File) -> 另存为(Save As)建议保存为:soak.jmx
6 运行前最后检查什么
在点击运行前,先检查 4 件事:
- 登录、首页、衣物列表的请求都已经配好。
Authorization里使用的是${token}。汇总报告还在,察看结果树已经禁用或删除。- 当前线程组参数和当前场景一致,没有把基准测试参数误带到负载测试里。
7 三个场景分别看什么
- 基准测试:看单用户响应时间
- 负载测试:看目标并发下的响应时间和错误率
- 稳定性测试:看长时间运行后是否变慢、是否有错误累积
3.7 第七步:测试执行
前言
1 执行顺序
建议固定按照下面顺序:
- 先跑基准测试
- 再跑负载测试
- 最后跑稳定性测试
2 为什么不能直接先跑 30 并发
因为如果一上来就跑高并发:
- 你不知道系统本来有多快
- 出现问题时没有基线对比
3 执行时要观察什么
JMeter侧
- 平均响应时间
- P95(在聚合报告中有)
- 吞吐量
- 错误率

服务器侧
- CPU
- 内存
- 磁盘
- MySQL 连接数
3.8 第八步:结果分析
前言
1 先分析接口结果
假设跑完后发现:
- 登录:很快
- 首页事务:偏慢
- 衣物列表:正常
那么要说明:
- 慢的不是所有接口
- 而是首页链路更复杂
2 为什么首页事务可能比单接口慢
因为首页不是 1 个接口,而是 4 个接口组合:
- 用户资料
- 衣物
- 衣柜
- 统计
所以首页事务时间大于单个衣物列表时间,是正常的。
3 如何写分析结论
示例结论
在 30 并发下:
- 登录接口响应稳定,满足目标。
- 用户首页事务响应时间高于单接口,但整体仍在可接受范围内。
- 用户衣物列表接口稳定,错误率较低。
- 当前系统可以支撑基础用户浏览场景。
4 如果结果不达标怎么办
如果发现首页事务偏慢,可以进一步看:
- 是哪个接口最慢。
- 是后端慢,还是数据库慢。
- 是不是数据量太小/太大导致测试失真。

