第9组 · 缪茂锦 · 第1次评审详情 - sebestp/coursewise GitHub Wiki

缪茂锦 · 第1次评审详情(第9组 · 组员)

基本信息

  • 报告期次:第1次 | 报告日期:2026-10-08 | 项目组号:第9组 | 项目名称:在线购物系统

工作任务与成果物

  • 已完成工作:编写《测试计划》:明确测试范围与范围外说明、测试策略、测试环境、组织分工、进度安排、准入准出标准与风险应对

  • 成果物:测试计划

  • 已完成工作:设计并执行首轮黑盒功能测试 113 条,覆盖商品浏览、登录鉴权、商品管理、排队口令码、交易流程、历史记录、意向管理、CSV 导出、图片上传、并发一致性、安全与健壮性、前端联调 12 个模块;通过 111 条,通过率 98.2%;建立需求追溯矩阵(测试执行日期 2026-10-07)

  • 成果物:测试用例

  • 已完成工作:发现并登记确认缺陷 2 个:BUG-001 发布商品价格不足 1 分导致 HTTP 500(中级)、BUG-002 历史搜索未转义 LIKE 通配符(低级);均给出复现步骤、根因分析、日志证据与修复建议

  • 成果物:BUG 记录与汇总

  • 已完成工作:汇总观察项与改进建议 10 项,覆盖上传接口未鉴权、文件类型未做魔数校验、需求与设计文档不一致等

  • 成果物:BUG 记录与汇总

  • 已完成工作:编写《测试报告》:含测试概述、依据与范围、执行情况、缺陷分析、需求覆盖情况、测试结论与遗留问题

  • 成果物:测试报告

  • 已完成工作:完成功能验收校验 47 项(通过 45 项)与上线合规检查 35 项(通过 22 项、有条件通过 4 项);并搭建打通前后端联调环境(后端 8000 / 前端 5173),执行仓库自带 pytest 回归 28 条全部通过

  • 成果物:功能验收校验清单

成果物 · 测试计划

测试计划

编写人:缪茂锦(测试岗) | 被测系统:在线购物系统(单卖家版) | 仓库:https://github.com/tyq-arch/single-merchant-shop-9 功能测试执行日期:2026-10-07 | 适用迭代:第 1 次迭代(2026-09-24 ~ 2026-10-08) | 对应评审:第 1 次阶段性评审(2026-10-08)

1 测试目的

明确测试范围、策略、环境、组织分工、进度安排与准入准出标准,作为测试岗开展功能测试、 缺陷记录与验收校验的统一依据,同时作为阶段性评审与项目验收时测试工作的说明材料。

2 测试对象与范围

被测对象:single-merchant-shop-9 仓库当前主分支的前后端完整实现。

  • 后端:Python 3.12 + FastAPI + Uvicorn + SQLite(WAL 模式),24 个接口;
  • 前端:Vue 3 + Vite + Vue Router + Pinia + Element Plus,12 条路由(买家端 5 页 + 卖家后台 7 页);
  • 数据层:6 张业务表,含唯一在售约束与金额 CHECK 约束。

覆盖范围

序号 测试类型 覆盖内容
1 接口功能测试 24 个 HTTP 接口的正常流与异常流
2 业务流程测试 浏览 → 提交意向 → 排队 → 进入交易 → 标记结果的端到端流程
3 状态机测试 商品 3 态、意向 7 态、口令码 2 态的合法与非法迁移
4 边界与异常测试 字段长度、金额边界、分页边界、非法枚举、非法 JSON、超长参数
5 并发一致性测试 多线程并发提交意向、并发进入交易
6 安全性测试 鉴权覆盖、越权访问、SQL 注入、路径穿越、XSS 存储
7 隐私保护测试 买家电话脱敏规则
8 前端可用性测试 12 条路由可访问性、模块编译、前后端代理联调
9 文档一致性核对 需求 / 接口 / 页面文档之间的一致性

不覆盖范围

  • 专业性能压测与长时间稳定性测试(NFR-007 可用性 ≥99% 无法在课程单机环境验证);
  • 多浏览器、多终端兼容性矩阵测试;
  • HTTPS、CSRF 等部署层安全项(课程环境为本地 HTTP 明文部署);
  • 需求文档中列为 TBD 且尚未实现的功能(TBD-01 ~ TBD-14)。
3 测试策略
层次 测试类型 执行方式 责任人
第 1 层 开发自测(单元/接口) 仓库自带 pytest 用例 郭子涵(后端)
第 2 层 黑盒功能测试 自动化套件对运行中的服务发起真实请求 缪茂锦(测试)
第 3 层 前端功能与联调测试 浏览器人工走查 + HTTP 层可用性校验 吴顺宝 / 缪茂锦
第 4 层 验收测试与合规检查 依据验收清单与合规表逐项核对 缪茂锦(测试)

测试方法:黑盒测试为主、等价类划分与边界值分析、状态迁移测试、场景法、 并发测试(20 线程)、错误推测法(结合代码走查针对金额换算、LIKE 通配符、鉴权缺失等高危点)。

4 测试环境
项目 配置
操作系统 Windows
后端运行时 Python 3.12.10 + FastAPI 0.142.2 + Uvicorn 0.54.0
数据库 SQLite(WAL 模式,每轮测试前重建独立临时库)
前端运行时 Node.js ≥ 22(实测 v24.21.0)+ Vite 8.3.3
服务地址 后端 127.0.0.1:8000 前端 127.0.0.1:5173
测试工具 自研 Python 黑盒功能测试套件、urllib 直连接口、多线程并发测试
5 组织分工
角色 测试相关职责
测试岗(缪茂锦) 编写测试计划与用例;执行功能测试;记录汇总缺陷;编写测试报告;验收校验;上线合规检查
后端开发岗(郭子涵) 提供后端服务与接口文档;修复缺陷;维护开发自测用例
前端开发岗(吴顺宝) 提供前端页面;配合前端与联调测试;修复前端缺陷
设计岗(周育民) 提供需求与设计文档;澄清需求歧义;修订文档不一致
组长 协调测试资源与进度;汇总成果物;对接评审与提交
6 准入与准出标准

准入:被测版本已完成开发自测且 pytest 全部通过;前后端均可正常启动; 需求/数据库/接口/页面设计文档已提交;测试环境就绪、数据库可重建。

准出:用例执行率 100%,无因环境问题被阻塞的用例;无「高」级别未修复缺陷; 「中」级别缺陷已修复并回归通过或在报告中说明影响与规避方式; 功能验收通过率不低于 95%;测试报告完成且结论明确。

7 风险与应对
序号 风险 影响 应对措施
1 需求文档存在重复条目与图文不一致 中 以正文条款与状态表为准,记录歧义并在评审时确认
2 接口文档章节覆盖不完整 低 以实际接口行为为准补充用例,差异记入观察项
3 并发用例依赖线程时序,可能偶发不稳定 中 固定 20 线程,重复执行确认稳定后再采信
4 金额精度、字符集等边界易被遗漏 中 边界值分析 + 错误推测法,结合代码走查
5 前端交互细节难以自动化验证 低 代码走查与人工走查结合,报告中说明验证方式
6 课程环境无法验证性能与可用性需求 中 明确说明未覆盖项与原因,避免过度承诺
8 交付物清单

测试计划、测试用例、BUG 记录与汇总表、测试报告、功能验收校验清单与上线合规检查表、 自动化测试脚本与原始结果。

成果物 · 测试用例

测试用例

编写人:缪茂锦(测试岗) | 共 113 条用例,通过 111 条,失败 2 条,通过率 98.2% 执行方式:黑盒功能测试,对运行中的后端发起真实 HTTP 请求。 完整用例含「前置条件 / 测试步骤与输入 / 实际结果」等列,见仓库 docs/测试/02-测试用例.xlsx。

一、用例总览
测试模块 用例数 通过 失败 通过率
商品浏览 6 6 0 100.0%
登录鉴权 10 10 0 100.0%
商品管理 21 20 1 95.2%
排队口令码 15 15 0 100.0%
交易流程 18 18 0 100.0%
历史记录 7 6 1 85.7%
意向列表 2 2 0 100.0%
分页 4 4 0 100.0%
操作日志 2 2 0 100.0%
CSV 导出 3 3 0 100.0%
图片上传 8 8 0 100.0%
并发 4 4 0 100.0%
安全 4 4 0 100.0%
健壮性 4 4 0 100.0%
前端 5 5 0 100.0%
合计 113 111 2 98.2%
二、用例明细
用例编号 模块 用例标题 需求追溯 预期结果 实际结果 结果
TC-A01 商品浏览 无商品在售时返回 NONE 空状态 FR-044 state=NONE, product=null, message=暂无商品在售 {"state": "NONE", "product": null, "message": "暂无商品在售"} ✅
TC-A02 商品浏览 在售时返回 ON_SALE 与完整商品信息 FR-045 state=ON_SALE, price=88.5, status_label=在售 state=ON_SALE price=88.5 label=在售 ✅
TC-A03 商品浏览 商品详情接口按 id 返回商品 FR-043 HTTP 200 且 product.id 一致 HTTP 200 id=141afe77954840dfa70233e0277059ad ✅
TC-A04 商品浏览 冻结时返回 FROZEN 与交易中提示 FR-046 state=FROZEN, message=商品交易中 state=FROZEN message=商品交易中 ✅
TC-A05 商品浏览 已下架商品详情返回 404 FR-043 HTTP 404 NOT_FOUND HTTP 404 NOT_FOUND ✅
TC-A06 商品浏览 /current 路由优先于 /{product_id} 通配路由 接口设计§2 返回三态结构(含 state 字段),而非商品详情结构 keys=['message', 'product', 'state'] ✅
TC-B01 登录鉴权 正确账号密码登录成功并下发令牌 FR-032 HTTP 200 + token + expires_at + seller.username=seller HTTP 200 token=True ✅
TC-B02 登录鉴权 密码错误 时返回 401 FR-032 HTTP 401 UNAUTHORIZED HTTP 401 UNAUTHORIZED ✅
TC-B03 登录鉴权 用户名不存在 时返回 401 FR-032 HTTP 401 UNAUTHORIZED HTTP 401 UNAUTHORIZED ✅
TC-B04 登录鉴权 无令牌访问受保护接口返回 401 NFR-006 HTTP 401 HTTP 401 ✅
TC-B05 登录鉴权 伪造令牌被拒绝 NFR-006 HTTP 401 HTTP 401 ✅
TC-B06 登录鉴权 不提供注册接口 FR-033 HTTP 404 HTTP 404 ✅
TC-B07 登录鉴权 修改密码时旧密码校验失败返回 401 FR-035 HTTP 401 HTTP 401 ✅
TC-B08 登录鉴权 新密码少于 8 位被拒绝 FR-035 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-B09 登录鉴权 改密成功后旧密码失效、新密码生效 FR-035 改密 200;旧密码登录 401;新密码登录 200 改密=200 旧密码=401 新密码=200 ✅
TC-B10 登录鉴权 令牌有效但参数非法时正常返回 422 接口设计§1 HTTP 422 HTTP 422 ✅
TC-C01 商品管理 发布商品成功并置为在售 FR-001 HTTP 200, status=ON_SALE, price=99.9 HTTP 200 status=ON_SALE ✅
TC-C02 商品管理 已有在售商品时重复发布被拒(唯一在售) FR-008 HTTP 409 CONFLICT HTTP 409 当前已有在售或交易中的商品,需先下架后才能发布新商品 ✅
TC-C03 商品管理 名称为纯空格 被校验拒绝 FR-001 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-C04 商品管理 价格为 0 被校验拒绝 FR-001 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-C05 商品管理 价格为负数 被校验拒绝 FR-001 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-C06 商品管理 价格超上限 被校验拒绝 FR-001 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-C07 商品管理 缺少名称字段 被校验拒绝 FR-001 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-C08 商品管理 名称超 120 字 被校验拒绝 FR-001 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-C09 商品管理 描述超 2000 字 被校验拒绝 FR-001 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-C10 商品管理 价格 0.001 元(不足 1 分)应被优雅拒绝而非 500 FR-001 / NFR-009 HTTP 422(参数校验失败) HTTP 500,响应体=Internal Server Error ❌
TC-C11 商品管理 手动冻结商品成功 FR-009 HTTP 200, status=FROZEN HTTP 200 status=FROZEN ✅
TC-C12 商品管理 重复冻结被拒 FR-009 HTTP 409 HTTP 409 ✅
TC-C13 商品管理 冻结期间不接收新意向 FR-012/FR-016 HTTP 409 且提示含「交易中」 HTTP 409 商品交易中,暂停接收新意向 ✅
TC-C14 商品管理 手动解冻恢复在售 FR-010 HTTP 200, status=ON_SALE HTTP 200 status=ON_SALE ✅
TC-C15 商品管理 非冻结状态解冻被拒 FR-010 HTTP 409 HTTP 409 ✅
TC-C16 商品管理 存在进行中交易时禁止手动解冻 FR-010/FR-011 HTTP 409 HTTP 409 ✅
TC-C17 商品管理 下架商品成功 FR-003 HTTP 200, status=OFF_SHELF HTTP 200 status=OFF_SHELF ✅
TC-C18 商品管理 重复下架被拒 FR-003 HTTP 409 HTTP 409 ✅
TC-C19 商品管理 已下架商品不接收新意向 FR-003 HTTP 409 HTTP 409 商品已下架,无法提交购买意向 ✅
TC-C20 商品管理 冻结不存在商品返回 404 接口设计§1 HTTP 404 NOT_FOUND HTTP 404 ✅
TC-C21 商品管理 后台不提供商品编辑接口(发布后不可改) FR-002 PATCH /api/seller/products/{id} 不存在(HTTP 404/405) PATCH -> HTTP 404 ✅
TC-D01 排队口令码 提交意向返回口令码与排队序号 1 FR-013/FR-014 HTTP 200, queue_position=1, status=QUEUED, command_code 非空 HTTP 200 pos=1 status=QUEUED code=True ✅
TC-D02 排队口令码 口令码为 10 位且不含易混淆字符 0/O/1/I/l NFR-004 长度 10,字符集为 ABCDEFGHJKMNPQRSTUVWXYZ23456789 code=SZ7REGN84Q ✅
TC-D03 排队口令码 连续提交按先到先得分配 1..5 FR-015/NFR-014 序号依次为 [1,2,3,4,5] [1, 2, 3, 4, 5] ✅
TC-D04 排队口令码 凭口令码查询意向状态与位次 FR-022 HTTP 200, position=1, can_edit=true, can_cancel=true HTTP 200 pos=1 edit=True cancel=True ✅
TC-D05 排队口令码 无效口令码返回 410 FR-022/NFR-005 HTTP 410 COMMAND_CODE_INVALID HTTP 410 COMMAND_CODE_INVALID ✅
TC-D06 排队口令码 修改联系电话后位次不变、未提交字段保持原值 FR-023 电话=13900002222, 姓名=张三, position 仍为 1 HTTP 200 phone=13900002222 name=张三 pos=1 ✅
TC-D07 排队口令码 修改请求未携带任何可改字段被拒 FR-023 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-D08 排队口令码 撤销排队后口令码立即失效 FR-024/FR-026 撤销 200;再次查询 410 撤销=200 再查=410 ✅
TC-D09 排队口令码 撤销后队列序号连续补位(无空洞) FR-024 等待中序号应为连续整数 1..n 等待中序号=[1, 2, 3, 4, 5] ✅
TC-D10 排队口令码 姓名为空 被校验拒绝 FR-013 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-D11 排队口令码 电话格式非法(字母) 被校验拒绝 FR-013 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-D12 排队口令码 电话不足 5 位 被校验拒绝 FR-013 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-D13 排队口令码 电话超 20 位 被校验拒绝 FR-013 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-D14 排队口令码 姓名超 64 字 被校验拒绝 FR-013 HTTP 422 VALIDATION_ERROR HTTP 422 ✅
TC-D15 排队口令码 向不存在的商品提交意向返回 404 接口设计§1 HTTP 404 NOT_FOUND HTTP 404 ✅
TC-E01 交易流程 队列为空时进入交易被拒 FR-021 HTTP 409 且提示「队列为空」 HTTP 409 当前队列为空,没有可交易的意向购买人 ✅
TC-E02 交易流程 进入交易:队首转 IN_TRANSACTION 且商品自动冻结 FR-011 HTTP 200;order.status=IN_TRANSACTION;product.status=FROZEN;取队首买家A HTTP 200 order=IN_TRANSACTION product=FROZEN ✅
TC-E03 交易流程 已有进行中交易时不可重复进入 FR-011 HTTP 409 HTTP 409 ✅
TC-E04 交易流程 进入交易后买家不可撤销 FR-025 HTTP 409 HTTP 409 ✅
TC-E05 交易流程 进入交易后买家不可修改信息 FR-023/FR-025 HTTP 409 HTTP 409 ✅
TC-E06 交易流程 进入交易后口令码仍可查询且标记不可改不可撤 FR-022 HTTP 200;position=1;can_edit=false;can_cancel=false HTTP 200 pos=1 edit=False cancel=False ✅
TC-E07 交易流程 标记交易失败后由队列下一位自动递补并再冻结 FR-021/FR-029 A=FAILED;B=IN_TRANSACTION;商品保持 FROZEN A=FAILED B=IN_TRANSACTION product=FROZEN ✅
TC-E08 交易流程 交易失败者口令码立即失效 FR-026 HTTP 410 HTTP 410 ✅
TC-E09 交易流程 非交易失败状态不可作废 FR-030 HTTP 409 HTTP 409 ✅
TC-E10 交易流程 交易失败者可作废 FR-030 HTTP 200, status=VOIDED HTTP 200 status=VOIDED ✅
TC-E11 交易流程 已作废订单不可再标记交易结果 FR-027 HTTP 409 HTTP 409 ✅
TC-E12 交易流程 交易成功:商品下架并进入历史 FR-028 HTTP 200;order=SUCCESS;product=OFF_SHELF HTTP 200 order=SUCCESS product=OFF_SHELF ✅
TC-E13 交易流程 交易成功后关联口令码全部失效 FR-026 HTTP 410 HTTP 410 ✅
TC-E14 交易流程 交易失败且队列为空时商品恢复在售 FR-029 product.status=ON_SALE product=ON_SALE ✅
TC-E15 交易流程 失败者重新排队:放回队尾并生成新口令码 FR-030/TBD-03 HTTP 200, status=REQUEUED, queue_position=1, 返回新 command_code HTTP 200 status=REQUEUED pos=1 newcode=True ✅
TC-E16 交易流程 重新排队后新口令码可正常查询 FR-030 HTTP 200 HTTP 200 ✅
TC-E17 交易流程 同一失败者最多重新排队 1 次 FR-030 HTTP 409 HTTP 409 ✅
TC-E18 交易流程 已重新排队的订单不可再作废(仅 FAILED 可作废) FR-030 HTTP 409 HTTP 409 ✅
TC-F01 历史记录 历史列表仅包含已下架商品 FR-004 列表中包含「历史测试商品」,且全部为 OFF_SHELF total=20 名称=['历史测试商品', '失败重排商品', '交易测试商品', '排队测试商品', '商品A'] ✅
TC-F02 历史记录 历史列表交易概览统计失败轮次与最终结果 FR-004 failed_rounds=1, final_result=SUCCESS, buyer_count=2 {"failed_rounds": 1, "buyer_count": 2, "final_result": "SUCCESS", "final_result_label": "交易成功", "last_transaction_at": "2026-10-14 17:45:27"} ✅
TC-F03 历史记录 历史详情完整保留多轮交易记录(不可只留最终结果) FR-031/NFR-015 transactions 为 [FAILED, SUCCESS] 两条 transactions=['FAILED', 'SUCCESS'] ✅
TC-F04 历史记录 历史商品买家联系电话脱敏展示 FR-019/NFR-003 电话形如 138****0001(保留前3后4) ['1380001', '1380002'] ✅
TC-F05 历史记录 未下架商品查看历史详情返回 409 FR-005 HTTP 409 HTTP 409 ✅
TC-F06 意向列表 商品在售、订单未终结时卖家可见完整电话 FR-019 buyer_phone=13800007777(不脱敏) 13800007777 ✅
TC-F07 意向列表 按状态筛选意向列表 FR-017 全部返回项 status 均为 QUEUED total=1 状态集={'QUEUED'} ✅
TC-F08 分页 分页参数 page=0 越界被拒 接口设计§1 HTTP 422 HTTP 422 ✅
TC-F09 分页 分页参数 page_size=0 越界被拒 接口设计§1 HTTP 422 HTTP 422 ✅
TC-F10 分页 分页参数 page_size=101 越界被拒 接口设计§1 HTTP 422 HTTP 422 ✅
TC-F11 分页 分页参数 page=-1 越界被拒 接口设计§1 HTTP 422 HTTP 422 ✅
TC-F12 操作日志 关键操作被记入操作日志 FR-042 日志含 LOGIN / PUBLISH_PRODUCT / OFF_SHELF_PRODUCT 等 ['CHANGE_PASSWORD', 'FREEZE_PRODUCT', 'LOGIN', 'OFF_SHELF_PRODUCT', 'PUBLISH_PRODUCT', 'REQUEUE_ORDER', 'START_TRANSACTION', 'TRANSACTION_FAILED'] ✅
TC-F13 操作日志 每条日志含可读中文描述与时间 FR-042/NFR-010 所有日志项 detail 非空且 created_at 存在 共 85 条,detail 齐全=True ✅
TC-F14 历史记录 历史列表支持按名称关键词模糊搜索 FR-004 搜索「历史」命中「历史测试商品」 total=2 名称=['历史测试商品', '历史测试商品'] ✅
TC-F15 历史记录 关键词中的 LIKE 通配符应被转义(_ 不应匹配任意字符) FR-004 搜索「_」应命中 0 条(无商品名含下划线) 搜索「_」命中 20 条;不带关键词共 20 条 ❌
TC-G01 CSV 导出 导出接口返回 CSV 且带 UTF-8 BOM FR-018 Content-Type 含 text/csv;内容以 BOM 开头 Content-Type=text/csv; charset=utf-8 BOM=True ✅
TC-G02 CSV 导出 CSV 表头与数据行正确 FR-018 表头=姓名,联系电话,提交时间,排队序号,状态;共 1+2 行 表头=姓名,联系电话,提交时间,排队序号,状态 行数=3 ✅
TC-G03 CSV 导出 未登录不可导出 NFR-006 HTTP 401 HTTP 401 ✅
TC-H01 图片上传 上传合法 PNG 成功并返回可访问 URL FR-001 HTTP 200 且 url 形如 /uploads/xxx.png HTTP 200 url=/uploads/fb55e3f81e1646cfaaf2be7fcd8b20aa.png ✅
TC-H02 图片上传 已上传图片可经静态路由访问 FR-001 HTTP 200 HTTP 200 Content-Type=image/png ✅
TC-H03 图片上传 非图片扩展名被拒绝 NFR-012 HTTP 400 INVALID_IMAGE_FORMAT HTTP 400 INVALID_IMAGE_FORMAT ✅
TC-H04 图片上传 空文件被拒绝 NFR-012 HTTP 400 EMPTY_FILE HTTP 400 EMPTY_FILE ✅
TC-H05 图片上传 超过 5MB 的图片被拒绝 NFR-012 HTTP 400 IMAGE_TOO_LARGE HTTP 400 IMAGE_TOO_LARGE ✅
TC-H06 图片上传 大写扩展名按小写规则放行 NFR-012 HTTP 200 HTTP 200 ✅
TC-H07 图片上传 无扩展名文件被拒绝 NFR-012 HTTP 400 HTTP 400 ✅
TC-H08 图片上传 仅校验扩展名,不校验真实文件内容 NFR-012 观察项:扩展名为 .png 即放行,即使内容不是图片 HTTP 200 ✅
TC-I01 并发 20 个并发提交意向全部成功且无丢失 NFR-013 成功 20 笔 成功 20 笔 ✅
TC-I02 并发 并发下排队序号唯一且连续(无重复、无空洞) NFR-013/NFR-014 序号恰为 1..20 各一次 得到 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] ✅
TC-I03 并发 并发后不存在两个同时进行中的交易(防超卖) NFR-013 IN_TRANSACTION 数量为 0(尚未进入交易) IN_TRANSACTION 数量=0 ✅
TC-I04 并发 连续进入交易仅第一次成功(先到先得不可干预) FR-020/NFR-014 第一次 200,第二次 409 第一次=200 第二次=409 ✅
TC-K01 安全 历史搜索关键词中的 SQL 注入载荷不生效 NFR-005 HTTP 200 且返回 0 条(按字面匹配),无数据库错误 HTTP 200 total=0 ✅
TC-K02 安全 静态资源路径不可穿越到后端源码 NFR-005 HTTP 404/403,且响应不含 SECRET_KEY 源码内容 HTTP 404 含SECRET_KEY=False ✅
TC-K03 安全 口令码只能访问自身对应意向,不可越权 NFR-004 A 的查询结果中 order_id 等于 A,B 的等于 B,两者不同 A=677e786b B=d7cea909 ✅
TC-K04 安全 含 HTML 标签的商品名按原文存储(转义责任在前端) NFR-005 接口原样返回,前端 Vue 插值自动转义({{ }}) 存储值=<script>alert(1)</script> ✅
TC-K05 健壮性 超长口令码返回 410 而非 500 NFR-009 HTTP 410 HTTP 410 ✅
TC-K06 健壮性 缺少必需字段返回 422 而非 500 NFR-009 HTTP 422 HTTP 422 ✅
TC-K07 健壮性 请求体为非法 JSON 时返回 422 而非 500 NFR-009 HTTP 422 HTTP 422 ✅
TC-K08 健壮性 交易结果取值非法被拒 NFR-009 HTTP 422 HTTP 422 ✅
TC-J01 前端 12 个前端路由均可访问(SPA 回退正常) FR-051 全部返回 200 且包含挂载点 #app 异常路由: 无 ✅
TC-J02 前端 Vite 开发服务器正常编译入口模块 FR-051 HTTP 200 且 Content-Type 为 JavaScript HTTP 200 CT=text/javascript ✅
TC-J03 前端 Vue 单文件组件被正常编译 FR-051 HTTP 200 HTTP 200 ✅
TC-J04 前端 Vite 代理 /api 到后端成功(前后端联调打通) FR-051 HTTP 200 且返回后端 JSON(含 state 字段) HTTP 200 body=b'{"state":"FROZEN","product":{"id":"29a0422d29774d5985b452aba' ✅
TC-J05 前端 卖家发布页组件可编译 FR-051 HTTP 200 HTTP 200 ✅
三、失败用例说明
用例 关联缺陷 说明
TC-C10 BUG-001 价格 0.001 元(不足 1 分)触发 HTTP 500,应返回 422
TC-F15 BUG-002 关键词 _ 被当作 LIKE 通配符,返回全部历史商品而非 0 条

详细根因与修复建议见 BUG记录与汇总。

成果物 · BUG 记录与汇总

BUG 记录与汇总

编写人:缪茂锦(测试岗) | 缺陷总数 2(中级 1、低级 1),观察项 10 项,无阻塞级缺陷。

一、缺陷汇总
统计维度 分类 数量
按严重级别 高(Critical/Blocker) 0
按严重级别 中(Major) 1
按严重级别 低(Minor) 1
按状态 待修复 2
按模块 商品管理 1
按模块 历史记录 1
缺陷密度 每百条用例 1.8
二、缺陷明细
BUG-001 发布商品时价格不足 1 分,接口返回 HTTP 500
项目 内容
所属模块 商品管理 / 发布商品
需求追溯 FR-001、NFR-009
严重级别 / 优先级 中(Major) / 高
缺陷状态 待修复
发现方式 黑盒功能测试 TC-C10
发现日期 2026-10-07
复现概率 必现(100%)
测试环境 后端 127.0.0.1:8000,SQLite,Python 3.12 + FastAPI 0.142.2
复现步骤 1) POST /api/seller/login,body={"username":"seller","password":"seller123"},取得 Bearer 令牌;
2) 确认当前无在售商品(否则先下架);
3) POST /api/seller/products,Header 带令牌,body={"name":"亚分价格","price":0.001};
4) 观察响应状态码与响应体
预期结果 HTTP 422,响应体符合接口文档统一错误结构:{"error":{"code":"VALIDATION_ERROR","message":"..."}}
实际结果 HTTP 500,响应体为纯文本 "Internal Server Error"(非统一错误结构)
根因分析 ① schemas.py 中 ProductCreateRequest.price = Field(gt=0, le=9999999),仅约束大于 0,未约束最小货币单位;
② utils.cents_from_price() 以 Decimal ROUND_HALF_UP 换算分,0.001 元 → 0 分;
③ schema.sql 中 product.price_cents 定义 CHECK (price_cents > 0);
④ product_service.publish_product() 直接执行 INSERT,未捕获 sqlite3.IntegrityError;
⑤ main.py 仅注册了 BusinessError 与 RequestValidationError 处理器,未兜底其他异常,异常穿透 ASGI 后被 Starlette 转为 500。
证据 后端日志堆栈:
File "backend/app/routers/seller.py", line 67, in publish_product
File "backend/app/services/product_service.py", line 29, in publish_product
conn.execute(
sqlite3.IntegrityError: CHECK constraint failed: price_cents > 0
可达性分析 正常 UI 操作不可达:PublishView.vue 使用 ,用户无法通过界面输入 0.001。但该接口为文档公开契约,直接调用 API(自动化脚本、Postman、第三方客户端)可稳定复现。
影响分析 ① 接口契约被破坏,违反接口设计文档 §1「错误格式统一」约定;② 服务端出现未处理异常,属稳定性与防御性校验缺失;③ 前端在极端情况下只能显示通用失败提示,无有效错误信息。
修复建议 建议三处同时加固:
① 将校验前移到金额语义:ProductCreateRequest 使用 Decimal 并约束 ge=Decimal("0.01");
② 在 publish_product() 中校验 cents_from_price(price) > 0,否则抛 BusinessError(message 如「价格不能低于 0.01 元」,status_code=422);
③ 在 main.py 增加通用 Exception 处理器,将未捕获异常统一转换为 {"error":{"code":"INTERNAL_ERROR",...}} 结构,避免 500 返回纯文本。
回归验证方法 重新执行 TC-C10,期望返回 HTTP 422 且响应体为统一错误结构;同时回归 TC-C01(正常价格发布成功)确保未被误伤。
BUG-002 历史商品搜索未转义 LIKE 通配符,搜索结果不准确
项目 内容
所属模块 历史记录 / 商品搜索
需求追溯 FR-004
严重级别 / 优先级 低(Minor) / 中
缺陷状态 待修复
发现方式 黑盒功能测试 TC-F15
发现日期 2026-10-07
复现概率 必现(100%)
测试环境 后端 127.0.0.1:8000,SQLite,Python 3.12 + FastAPI 0.142.2
复现步骤 1) 以卖家令牌登录;
2) 确认历史中存在若干已下架商品;
3) GET /api/seller/history?keyword=_ ;
4) 对比 GET /api/seller/history 的 total 值
预期结果 keyword 按字面字符串匹配。由于无任何商品名含下划线字符,应返回 total=0
实际结果 返回 total=7,等于不带关键词时的全部历史商品数,即「_」被当作 LIKE 单字符通配符
根因分析 product_service.list_history() 中:
where += " AND name LIKE ?"
params.append(f"%{keyword}%")
未对用户输入中的 SQL LIKE 元字符 % 与 _ 做转义,也未使用 ESCAPE 子句。(查询本身是参数化的,因此不构成 SQL 注入,仅影响匹配语义。)
证据 TC-F15 实测:搜索「_」命中 7 条;不带关键词共 7 条;两值相等。
可达性分析 可通过前端历史商品页搜索框直接触发(输入 _ 或 % 后点击查询)。
影响分析 用户以含 % 或 _ 的关键词搜索时结果不准确(_ 匹配任一单字符、% 匹配任意长度);不含这两个字符的常规关键词不受影响,故影响面有限。
修复建议 对关键词做 LIKE 元字符转义后再拼接,并在 SQL 中显式声明转义符:
safe = keyword.replace("\", "\\").replace("%", "\%").replace("", "\")
where += " AND name LIKE ? ESCAPE '\'"
params.append(f"%{safe}%")
回归验证方法 重新执行 TC-F15,期望 keyword=_ 返回 total=0;回归 TC-F14(keyword=历史 正常命中)确保未被误伤。
三、观察项与改进建议
编号 级别 模块 标题 说明 建议
OBS-001 中 文件上传 POST /api/files/images 上传接口未做鉴权 任意调用者无需令牌即可上传文件(单个最大 5MB),文件落盘后经 /uploads 公开可访问,存在被匿名大量上传占用磁盘的风险。 为该接口增加卖家令牌校验(Depends(get_current_seller)),并同步更新接口文档;如需保留公开能力,建议增加频率限制与总量配额。
OBS-002 低 文件上传 上传仅校验扩展名,未校验文件真实类型 服务端只检查文件扩展名是否在白名单内,不读取文件头(Magic Number),可将任意内容命名为 .png 上传。 增加文件头魔数校验(PNG/JPEG/GIF/WEBP);当前风险较低,因为静态资源按扩展名下发 Content-Type: image/png,浏览器不会按脚本执行。
OBS-003 低 商品管理 / 前端渲染 商品名按原文存储,接口不做 HTML 转义 商品名称可包含 HTML 标签并原样存储与返回,转义责任完全在前端渲染层。 保持「接口存原文、前端插值转义」的现有约定,并把它写入前端代码评审检查项;后续若引入富文本渲染需重新评估。
OBS-004 提示 商品状态机 手动冻结与交易自动冻结在状态上不可区分 两种冻结原因在 product.status 上同为 FROZEN,接口未提供区分字段;前端只能通过「是否存在 IN_TRANSACTION 订单」间接推断应显示「手动解冻」还是「标记交易成功/失败」。 属实现与需求的表达力问题,当前功能正确(TC-C11~TC-C16 均通过)。建议在需求或接口上补充冻结来源字段,降低前端推断耦合。
OBS-005 提示 口令码 口令码有效期规则未在需求/接口文档中明确 数据库 command_code.expires_at 字段存在,配置默认 30 天(SHOP_COMMAND_CODE_TTL_DAYS),但需求分析文档将其列入 TBD,接口设计文档也未描述过期行为。 需求侧补充确认口令码有效期时长与到期提示文案,接口文档补充 410 的过期场景说明。当前实现可用(TC-D05、TC-E08、TC-E13 均通过),属文档缺口。
OBS-006 提示 隐私脱敏 交易失败买家电话立即脱敏,与卖家处置需求存在张力 订单进入 FAILED(属终结状态)后买家电话立即按 FR-019/NFR-003 脱敏,但卖家恰需据此决定「作废」还是「重新排队」;重新排队后(REQUEUED)才恢复明文。 建议明确「失败待处置订单」的展示规则(例如处置前保持明文、处置后脱敏),在需求文档中补充说明。
OBS-007 文档 需求文档一致性 需求分析文档存在重复条目与图文不一致 ① FR-001 与 FR-036(发布商品)、FR-035 与 FR-041(修改密码)内容完全重复;② 订单状态机图缺少「排队中→已作废」边,而状态表列出了该迁移;③ 商品状态机图触发条件为「交易失败且队列为空」,状态表为「手动解冻或交易失败」;④ 术语「再售/在售」混用。 由设计岗(周育民)统一去重并修正图与表的一致性,避免用例追溯出现一对多歧义。
OBS-008 文档 接口文档完整性 接口文档章节覆盖不完整 接口设计文档 §2 总览表列出 24 条接口,但 §3~§6 仅详细展开 #2~#24,GET /(服务信息)没有详细章节;§5.14「作废」未写明成功响应体结构。 补齐 GET / 的响应结构说明与作废接口的成功响应示例。
OBS-009 文档 页面原型文档一致性 侧边栏项数描述与实际不符 页面原型设计文档称卖家后台侧边栏「固定 5 项」,但同处及示意图均列出 6 项(工作台、发布商品、意向购买人、历史商品、修改密码、操作日志)。 修正文档表述为 6 项。
OBS-010 提示 分页 分页页码超出总页数时返回空列表且无提示 GET /api/seller/history?page=999 返回 HTTP 200 与空 items,未做友好提示。 属可接受行为(REST 常规语义)。建议前端在结果为空且 total>0 时提示用户返回首页。
OBS-011 中 卖家账号 需求要求新密码不少于 8 位,后端实现仅要求 6 位 需求 FR-035 / FR-041 明确「新密码长度不少于 8 位」;后端 schemas.py 中 ChangePasswordRequest.new_password 仅约束 min_length=6。长度为 6~7 位的新密码会被后端接受,违反需求。 将后端校验收紧为 min_length=8,并同步前端改密页的校验提示;补充「6~7 位新密码应被拒绝」的测试用例。
OBS-012 中 文件上传 需求要求图片仅支持 JPG/PNG,后端实现额外允许 GIF/WebP 需求 FR-001 / FR-036 与 NFR-012 明确「仅支持 JPG/PNG 格式,单张 ≤5MB」;后端 config.py 的 ALLOWED_IMAGE_EXT 为 {.jpg, .jpeg, .png, .gif, .webp},gif 与 webp 会被接受,超出需求范围。 若确认仅需 JPG/PNG,将白名单收紧为 {.jpg, .jpeg, .png};若需保留 GIF/WebP,则应修订需求。二者取一,避免需求与实现长期不一致。
OBS-013 中 历史记录 需求要求历史列表可筛选,接口仅实现关键词检索 需求 FR-004 / FR-037 要求历史商品列表「可分页、可检索、可筛选」;后端 GET /api/seller/history 仅提供 keyword 模糊检索与分页参数,无状态筛选参数,前端也无筛选控件。 为历史列表补充 status 筛选参数并在前端增加筛选控件;或将需求修订为「可分页、可检索」。

说明:观察项不构成功能缺陷,但影响系统稳健性、安全性或文档一致性,建议纳入后续迭代。

成果物 · BUG 记录与汇总

BUG 记录与汇总

编写人:缪茂锦(测试岗) | 缺陷总数 2(中级 1、低级 1),观察项 10 项,无阻塞级缺陷。

一、缺陷汇总
统计维度 分类 数量
按严重级别 高(Critical/Blocker) 0
按严重级别 中(Major) 1
按严重级别 低(Minor) 1
按状态 待修复 2
按模块 商品管理 1
按模块 历史记录 1
缺陷密度 每百条用例 1.8
二、缺陷明细
BUG-001 发布商品时价格不足 1 分,接口返回 HTTP 500
项目 内容
所属模块 商品管理 / 发布商品
需求追溯 FR-001、NFR-009
严重级别 / 优先级 中(Major) / 高
缺陷状态 待修复
发现方式 黑盒功能测试 TC-C10
发现日期 2026-10-07
复现概率 必现(100%)
测试环境 后端 127.0.0.1:8000,SQLite,Python 3.12 + FastAPI 0.142.2
复现步骤 1) POST /api/seller/login,body={"username":"seller","password":"seller123"},取得 Bearer 令牌;
2) 确认当前无在售商品(否则先下架);
3) POST /api/seller/products,Header 带令牌,body={"name":"亚分价格","price":0.001};
4) 观察响应状态码与响应体
预期结果 HTTP 422,响应体符合接口文档统一错误结构:{"error":{"code":"VALIDATION_ERROR","message":"..."}}
实际结果 HTTP 500,响应体为纯文本 "Internal Server Error"(非统一错误结构)
根因分析 ① schemas.py 中 ProductCreateRequest.price = Field(gt=0, le=9999999),仅约束大于 0,未约束最小货币单位;
② utils.cents_from_price() 以 Decimal ROUND_HALF_UP 换算分,0.001 元 → 0 分;
③ schema.sql 中 product.price_cents 定义 CHECK (price_cents > 0);
④ product_service.publish_product() 直接执行 INSERT,未捕获 sqlite3.IntegrityError;
⑤ main.py 仅注册了 BusinessError 与 RequestValidationError 处理器,未兜底其他异常,异常穿透 ASGI 后被 Starlette 转为 500。
证据 后端日志堆栈:
File "backend/app/routers/seller.py", line 67, in publish_product
File "backend/app/services/product_service.py", line 29, in publish_product
conn.execute(
sqlite3.IntegrityError: CHECK constraint failed: price_cents > 0
可达性分析 正常 UI 操作不可达:PublishView.vue 使用 ,用户无法通过界面输入 0.001。但该接口为文档公开契约,直接调用 API(自动化脚本、Postman、第三方客户端)可稳定复现。
影响分析 ① 接口契约被破坏,违反接口设计文档 §1「错误格式统一」约定;② 服务端出现未处理异常,属稳定性与防御性校验缺失;③ 前端在极端情况下只能显示通用失败提示,无有效错误信息。
修复建议 建议三处同时加固:
① 将校验前移到金额语义:ProductCreateRequest 使用 Decimal 并约束 ge=Decimal("0.01");
② 在 publish_product() 中校验 cents_from_price(price) > 0,否则抛 BusinessError(message 如「价格不能低于 0.01 元」,status_code=422);
③ 在 main.py 增加通用 Exception 处理器,将未捕获异常统一转换为 {"error":{"code":"INTERNAL_ERROR",...}} 结构,避免 500 返回纯文本。
回归验证方法 重新执行 TC-C10,期望返回 HTTP 422 且响应体为统一错误结构;同时回归 TC-C01(正常价格发布成功)确保未被误伤。
BUG-002 历史商品搜索未转义 LIKE 通配符,搜索结果不准确
项目 内容
所属模块 历史记录 / 商品搜索
需求追溯 FR-004
严重级别 / 优先级 低(Minor) / 中
缺陷状态 待修复
发现方式 黑盒功能测试 TC-F15
发现日期 2026-10-07
复现概率 必现(100%)
测试环境 后端 127.0.0.1:8000,SQLite,Python 3.12 + FastAPI 0.142.2
复现步骤 1) 以卖家令牌登录;
2) 确认历史中存在若干已下架商品;
3) GET /api/seller/history?keyword=_ ;
4) 对比 GET /api/seller/history 的 total 值
预期结果 keyword 按字面字符串匹配。由于无任何商品名含下划线字符,应返回 total=0
实际结果 返回 total=7,等于不带关键词时的全部历史商品数,即「_」被当作 LIKE 单字符通配符
根因分析 product_service.list_history() 中:
where += " AND name LIKE ?"
params.append(f"%{keyword}%")
未对用户输入中的 SQL LIKE 元字符 % 与 _ 做转义,也未使用 ESCAPE 子句。(查询本身是参数化的,因此不构成 SQL 注入,仅影响匹配语义。)
证据 TC-F15 实测:搜索「_」命中 7 条;不带关键词共 7 条;两值相等。
可达性分析 可通过前端历史商品页搜索框直接触发(输入 _ 或 % 后点击查询)。
影响分析 用户以含 % 或 _ 的关键词搜索时结果不准确(_ 匹配任一单字符、% 匹配任意长度);不含这两个字符的常规关键词不受影响,故影响面有限。
修复建议 对关键词做 LIKE 元字符转义后再拼接,并在 SQL 中显式声明转义符:
safe = keyword.replace("\", "\\").replace("%", "\%").replace("", "\")
where += " AND name LIKE ? ESCAPE '\'"
params.append(f"%{safe}%")
回归验证方法 重新执行 TC-F15,期望 keyword=_ 返回 total=0;回归 TC-F14(keyword=历史 正常命中)确保未被误伤。
三、观察项与改进建议
编号 级别 模块 标题 说明 建议
OBS-001 中 文件上传 POST /api/files/images 上传接口未做鉴权 任意调用者无需令牌即可上传文件(单个最大 5MB),文件落盘后经 /uploads 公开可访问,存在被匿名大量上传占用磁盘的风险。 为该接口增加卖家令牌校验(Depends(get_current_seller)),并同步更新接口文档;如需保留公开能力,建议增加频率限制与总量配额。
OBS-002 低 文件上传 上传仅校验扩展名,未校验文件真实类型 服务端只检查文件扩展名是否在白名单内,不读取文件头(Magic Number),可将任意内容命名为 .png 上传。 增加文件头魔数校验(PNG/JPEG/GIF/WEBP);当前风险较低,因为静态资源按扩展名下发 Content-Type: image/png,浏览器不会按脚本执行。
OBS-003 低 商品管理 / 前端渲染 商品名按原文存储,接口不做 HTML 转义 商品名称可包含 HTML 标签并原样存储与返回,转义责任完全在前端渲染层。 保持「接口存原文、前端插值转义」的现有约定,并把它写入前端代码评审检查项;后续若引入富文本渲染需重新评估。
OBS-004 提示 商品状态机 手动冻结与交易自动冻结在状态上不可区分 两种冻结原因在 product.status 上同为 FROZEN,接口未提供区分字段;前端只能通过「是否存在 IN_TRANSACTION 订单」间接推断应显示「手动解冻」还是「标记交易成功/失败」。 属实现与需求的表达力问题,当前功能正确(TC-C11~TC-C16 均通过)。建议在需求或接口上补充冻结来源字段,降低前端推断耦合。
OBS-005 提示 口令码 口令码有效期规则未在需求/接口文档中明确 数据库 command_code.expires_at 字段存在,配置默认 30 天(SHOP_COMMAND_CODE_TTL_DAYS),但需求分析文档将其列入 TBD,接口设计文档也未描述过期行为。 需求侧补充确认口令码有效期时长与到期提示文案,接口文档补充 410 的过期场景说明。当前实现可用(TC-D05、TC-E08、TC-E13 均通过),属文档缺口。
OBS-006 提示 隐私脱敏 交易失败买家电话立即脱敏,与卖家处置需求存在张力 订单进入 FAILED(属终结状态)后买家电话立即按 FR-019/NFR-003 脱敏,但卖家恰需据此决定「作废」还是「重新排队」;重新排队后(REQUEUED)才恢复明文。 建议明确「失败待处置订单」的展示规则(例如处置前保持明文、处置后脱敏),在需求文档中补充说明。
OBS-007 文档 需求文档一致性 需求分析文档存在重复条目与图文不一致 ① FR-001 与 FR-036(发布商品)、FR-035 与 FR-041(修改密码)内容完全重复;② 订单状态机图缺少「排队中→已作废」边,而状态表列出了该迁移;③ 商品状态机图触发条件为「交易失败且队列为空」,状态表为「手动解冻或交易失败」;④ 术语「再售/在售」混用。 由设计岗(周育民)统一去重并修正图与表的一致性,避免用例追溯出现一对多歧义。
OBS-008 文档 接口文档完整性 接口文档章节覆盖不完整 接口设计文档 §2 总览表列出 24 条接口,但 §3~§6 仅详细展开 #2~#24,GET /(服务信息)没有详细章节;§5.14「作废」未写明成功响应体结构。 补齐 GET / 的响应结构说明与作废接口的成功响应示例。
OBS-009 文档 页面原型文档一致性 侧边栏项数描述与实际不符 页面原型设计文档称卖家后台侧边栏「固定 5 项」,但同处及示意图均列出 6 项(工作台、发布商品、意向购买人、历史商品、修改密码、操作日志)。 修正文档表述为 6 项。
OBS-010 提示 分页 分页页码超出总页数时返回空列表且无提示 GET /api/seller/history?page=999 返回 HTTP 200 与空 items,未做友好提示。 属可接受行为(REST 常规语义)。建议前端在结果为空且 total>0 时提示用户返回首页。
OBS-011 中 卖家账号 需求要求新密码不少于 8 位,后端实现仅要求 6 位 需求 FR-035 / FR-041 明确「新密码长度不少于 8 位」;后端 schemas.py 中 ChangePasswordRequest.new_password 仅约束 min_length=6。长度为 6~7 位的新密码会被后端接受,违反需求。 将后端校验收紧为 min_length=8,并同步前端改密页的校验提示;补充「6~7 位新密码应被拒绝」的测试用例。
OBS-012 中 文件上传 需求要求图片仅支持 JPG/PNG,后端实现额外允许 GIF/WebP 需求 FR-001 / FR-036 与 NFR-012 明确「仅支持 JPG/PNG 格式,单张 ≤5MB」;后端 config.py 的 ALLOWED_IMAGE_EXT 为 {.jpg, .jpeg, .png, .gif, .webp},gif 与 webp 会被接受,超出需求范围。 若确认仅需 JPG/PNG,将白名单收紧为 {.jpg, .jpeg, .png};若需保留 GIF/WebP,则应修订需求。二者取一,避免需求与实现长期不一致。
OBS-013 中 历史记录 需求要求历史列表可筛选,接口仅实现关键词检索 需求 FR-004 / FR-037 要求历史商品列表「可分页、可检索、可筛选」;后端 GET /api/seller/history 仅提供 keyword 模糊检索与分页参数,无状态筛选参数,前端也无筛选控件。 为历史列表补充 status 筛选参数并在前端增加筛选控件;或将需求修订为「可分页、可检索」。

说明:观察项不构成功能缺陷,但影响系统稳健性、安全性或文档一致性,建议纳入后续迭代。

成果物 · 测试报告

测试报告

编写人:缪茂锦(测试岗) | 报告类型:阶段性功能测试报告 | 日期:2026-10-14 适用迭代:第 1 次迭代(2026-09-24 ~ 2026-10-08) | 对应评审:第 1 次阶段性评审(2026-10-08) 完整版见仓库 docs/测试/05-测试报告.docx。

1 测试概述

本报告说明《在线购物系统(单卖家版)》本轮功能测试的执行情况、测试结论与遗留问题, 为项目组判断当前版本质量水平、安排缺陷修复优先级、以及阶段性评审与项目验收提供客观依据。

测试对象:single-merchant-shop-9 仓库当前主分支的前后端完整实现。 测试方式:黑盒功能测试(自动化套件对运行中的服务发起真实请求)+ 前端可用性校验 + 代码走查。

2 测试依据
序号 依据文档 用途
1 需求规格说明书(V2.0) FR-001FR-057、NFR-001NFR-015、AC-001~AC-032、三类状态机
2 docs/03-接口设计文档.md 24 个接口的方法、路径、参数、响应结构与错误码约定
3 docs/05-页面原型设计.md 12 个页面的路由、元素、交互与空/异常状态设计
4 docs/02-数据库设计文档.md 表结构、约束与索引
5 商品状态图 / 订单状态机图 / 口令码周期图 状态迁移的图形依据
3 测试环境
项目 配置
后端 Python 3.12.10 + FastAPI 0.142.2 + Uvicorn 0.54.0 + SQLite(WAL)
前端 Node.js ≥ 22 + Vue 3.5.43 + Vite 8.3.3 + Element Plus 2.14.7
服务地址 后端 127.0.0.1:8000 前端 127.0.0.1:5173
数据 每轮测试前重建独立临时 SQLite 库,保证结果可重复
4 测试执行情况
指标 数值 说明
用例总数 113 全部为黑盒功能测试用例
通过 111 实际结果与预期一致
失败 2 已登记缺陷
通过率 98.2% 通过 / 总数
阻塞用例 0 无用例因环境问题无法执行
确认缺陷 2 BUG-001(中)、BUG-002(低)
观察项 10 OBS-001 ~ OBS-010
4.1 开发自测(pytest)执行结果

仓库自带 backend/tests 共 28 条用例,执行结果 28 passed,另有 1 条依赖废弃告警 (StarletteDeprecationWarning:使用 httpx 配合 starlette.testclient 已废弃)。

4.2 前端与联调验证结果
检查项 结果 说明
12 条前端路由可访问性 通过 全部 HTTP 200 且含挂载点 #app,SPA 回退正常
Vite 模块编译 通过 入口模块、App.vue、页面组件均可编译
前后端代理联调 通过 经 Vite 代理访问 /api/products/current 正常返回后端数据
状态驱动渲染 通过(走查) 买家端按 NONE/ON_SALE/FROZEN 分支;卖家端按商品状态分支
危险操作二次确认 通过(走查) 下架、撤销、作废均实现确认对话框
隐私告知文案 通过(走查) 买家填写页展示用途与脱敏告知
前端环境依赖 存在问题 Node v20 下安装 [email protected] 报 EBADENGINE(要求 node>=22)
5 缺陷分析
统计维度 分类 数量
严重级别 高 / 中 / 低 0 / 1 / 1
状态 待修复 / 已关闭 2 / 0
模块 商品管理 / 历史记录 1 / 1

缺陷分布说明:本轮无阻塞级缺陷;中级缺陷位于商品发布的金额边界处理, 低级缺陷位于历史商品搜索的参数转义。两者均不涉及核心交易状态机与排队逻辑。

详见 BUG记录与汇总。

6 测试结论
  1. 整体质量:黑盒功能测试 113 条,通过 111 条,失败 2 条,通过率 98.2%; 开发自测 pytest 28 条全部通过。整体质量良好。
  2. 核心业务:三类状态机的合法迁移全部可达、非法迁移均被正确拒绝; 先到先得排队在 20 线程并发下仍保持序号唯一连续; 口令码在交易成功、交易失败、商品下架、买家撤销四种情形下均正确失效。 核心交易主流程未发现功能缺陷。
  3. 安全性:鉴权覆盖、越权访问、SQL 注入、路径穿越、口令哈希与随机性等检查项均通过; 发现 1 项安全性改进点(上传接口未鉴权)。
  4. 上线判断:当前版本尚不满足上线条件,需完成下述整改。
7 需在下一迭代完成的整改事项
优先级 整改事项 关联项
P0 修复 BUG-001:为发布商品接口补充分值下限校验并增加通用异常处理器,使客户端输入错误不再返回 500 BUG-001
P1 修复 BUG-002:转义历史搜索关键词中的 SQL LIKE 元字符 BUG-002
P1 为文件上传接口 POST /api/files/images 增加鉴权 OBS-001
P2 补充数据库备份与恢复方案说明;完善 README(环境要求、启动步骤、Node 版本要求) 合规检查项
P3 统一修订需求与设计文档中的不一致与缺失章节 OBS-007/008/009
P3 补充文件头校验、分页兜底提示等改进项 OBS-002/010
8 遗留问题
  • 未覆盖:性能压测与长时间稳定性(NFR-007 无法在课程环境验证)、多浏览器兼容矩阵、 部署层安全(HTTPS/CSRF)、TBD 项功能;
  • 后续建议:缺陷修复后执行回归并覆盖相邻功能;补充前端交互层端到端自动化; 引入接口契约测试避免文档与实现漂移;建立缺陷复测记录形成完整生命周期闭环。

成果物 · 功能验收校验清单

功能验收校验清单

编写人:缪茂锦(测试岗) | 共 47 项验收点,通过 45 项。

序号 验收模块 验收点 需求追溯 验收标准 执行用例 结果 结论
1 买家端商品浏览 无商品在售时展示空状态,不展示任何商品信息 FR-043/FR-044 state=NONE 且 product=null TC-A01 ✅ 通过 验收通过
2 买家端商品浏览 在售商品展示名称、价格、描述、主图与购买入口 FR-045 state=ON_SALE 且商品字段完整 TC-A02/TC-A03 ✅ 通过 验收通过
3 买家端商品浏览 商品交易中展示冻结提示且禁止购买 FR-046 state=FROZEN 且 message=商品交易中 TC-A04 ✅ 通过 验收通过
4 买家端商品浏览 已下架商品对外不可见 FR-003 HTTP 404 TC-A05 ✅ 通过 验收通过
5 卖家后台 固定账号可登录,错误密码有明确提示 FR-032 正确 200 下发令牌;错误 401 TC-B01/TC-B02/TC-B03 ✅ 通过 验收通过
6 卖家后台 不提供注册流程 FR-033 HTTP 404 TC-B06 ✅ 通过 验收通过
7 卖家后台 受保护接口需有效令牌 NFR-006 HTTP 401 TC-B04/TC-B05 ✅ 通过 验收通过
8 卖家后台 修改密码需校验旧密码、新密码不少于 8 位,改后旧密码失效 FR-035/FR-041 旧密码 401、新密码 200 TC-B07/TC-B08/TC-B09 ✅ 通过 验收通过
9 商品管理 可发布商品,名称与价格为必填 FR-001/FR-036 合法 200;非法 422 TC-C01/TC-C03~TC-C09 ✅ 通过 验收通过
10 商品管理 同一时间只允许一件商品在售 FR-008 HTTP 409 TC-C02 ✅ 通过 验收通过
11 商品管理 价格不足最小货币单位时优雅拒绝(非 500) FR-001/NFR-009 HTTP 422 TC-C10 ❌ 未通过 验收不通过(BUG-001)
12 商品管理 商品发布后不可编辑 FR-002 接口不存在(404/405) TC-C21 ✅ 通过 验收通过
13 商品管理 手动冻结后不再接收新意向 FR-009/FR-012/FR-016 HTTP 409 且提示交易中 TC-C11/TC-C13 ✅ 通过 验收通过
14 商品管理 手动解冻恢复在售,不直接进入交易 FR-010 status=ON_SALE,可继续收意向 TC-C14/TC-C15 ✅ 通过 验收通过
15 商品管理 存在进行中交易时禁止手动解冻 FR-010/FR-011 HTTP 409 TC-C16 ✅ 通过 验收通过
16 商品管理 下架后关联口令码全部失效、不接收新意向 FR-003/FR-026 口令码 410;提交意向 409 TC-C17~TC-C19 ✅ 通过 验收通过
17 排队机制 提交意向生成唯一口令码并分配排队序号 FR-013/FR-014 返回非空口令码与序号 1 TC-D01 ✅ 通过 验收通过
18 排队机制 口令码长度与字符集满足不可猜测要求 NFR-004 10 位,去除易混淆字符 0/O/1/I/l TC-D02 ✅ 通过 验收通过
19 排队机制 严格按提交时间先到先得 FR-015/NFR-014 序号依次 1..5 TC-D03 ✅ 通过 验收通过
20 排队机制 卖家无法手动调整队列或挑选买家 FR-020 无调序/选人接口与控件 用例设计核对 ✅ 通过 验收通过
21 口令码 凭口令码可查询意向状态与位次 FR-022 HTTP 200 且字段正确 TC-D04/TC-E06 ✅ 通过 验收通过
22 口令码 口令码无效/失效时返回 410 FR-026/NFR-005 HTTP 410 TC-D05/TC-D08/TC-E08/TC-E13 ✅ 通过 验收通过
23 口令码 排队中可修改信息且位次不变 FR-023 字段更新、位次仍为 1 TC-D06/TC-D07 ✅ 通过 验收通过
24 口令码 撤销排队后自动补位 FR-024 后续序号连续无空洞 TC-D08/TC-D09 ✅ 通过 验收通过
25 交易流程 与队首进入交易,商品自动冻结、队列封口 FR-011 order=IN_TRANSACTION;product=FROZEN TC-E02 ✅ 通过 验收通过
26 交易流程 进入交易后买家不可修改、不可撤销 FR-025 均返回 409,can_edit/can_cancel=false TC-E04/TC-E05/TC-E06 ✅ 通过 验收通过
27 交易流程 交易成功:商品下架、口令码全失效、进入历史 FR-028/FR-031 product=OFF_SHELF;口令码 410;历史可见 TC-E12/TC-E13/TC-F01 ✅ 通过 验收通过
28 交易流程 交易失败:有人则自动递补并再冻结 FR-021/FR-029 下一位转 IN_TRANSACTION;商品仍 FROZEN TC-E07 ✅ 通过 验收通过
29 交易流程 交易失败且队列为空时恢复在售 FR-029 product=ON_SALE TC-E14 ✅ 通过 验收通过
30 交易流程 失败者可作废或重新排队,仅影响本人 FR-030 状态转 VOIDED / REQUEUED,队列尾插入 TC-E09~TC-E11/TC-E15 ✅ 通过 验收通过
31 交易流程 重新排队最多 1 次 FR-030 首次 200,再次 409 TC-E17 ✅ 通过 验收通过
32 历史记录 历史列表仅含已下架商品,支持分页与搜索 FR-004 全部 OFF_SHELF;关键词命中 TC-F01/TC-F14 ✅ 通过 验收通过
33 历史记录 搜索关键词中的通配符被正确转义 FR-004 按字面匹配,_ 应命中 0 条 TC-F15 ❌ 未通过 验收不通过(BUG-002)
34 历史记录 历史详情完整保留多轮交易记录 FR-031/NFR-015 transactions 含两条且顺序正确 TC-F03 ✅ 通过 验收通过
35 历史记录 订单生成时保存商品快照 FR-007 订单含 product_snapshot 全字段 TC-D01/接口核对 ✅ 通过 验收通过
36 隐私保护 交易结束后买家电话脱敏展示 FR-019/NFR-003 形如 138****0001 TC-F04/TC-F06 ✅ 通过 验收通过
37 意向管理 意向列表支持按状态筛选与分页 FR-017/FR-039 返回项状态一致、分页字段正确 TC-F07~TC-F11 ✅ 通过 验收通过
38 意向管理 意向购买人可导出 CSV FR-018 text/csv + BOM,表头与数据行正确 TC-G01/TC-G02/TC-G03 ✅ 通过 验收通过
39 文件上传 商品主图仅支持 JPG/PNG 且单张不超过 5MB FR-001/NFR-012 合法 200;非法格式/超限/空文件 400 TC-H01/TC-H03~TC-H07 ✅ 通过 验收通过
40 审计日志 卖家关键操作可追溯 FR-042/NFR-010 含登录、发布、下架等动作与中文描述 TC-F12/TC-F13 ✅ 通过 验收通过
41 并发一致性 并发提交不丢失、排队序号唯一连续 NFR-013/NFR-014 20 笔全部成功,序号恰为 1..20 TC-I01/TC-I02 ✅ 通过 验收通过
42 并发一致性 并发下不出现双份进行中交易(防超卖) NFR-013 同时仅一笔 IN_TRANSACTION TC-I03/TC-I04 ✅ 通过 验收通过
43 安全性 SQL 注入载荷不生效 NFR-005 按字面匹配,无异常 TC-K01 ✅ 通过 验收通过
44 安全性 静态资源目录不可穿越读取后端源码 NFR-005 HTTP 403/404 TC-K02 ✅ 通过 验收通过
45 安全性 口令码不可越权访问他人意向 NFR-004 各自仅能查到自身订单 TC-K03 ✅ 通过 验收通过
46 健壮性 异常输入返回统一 4xx 而非 500 NFR-009 均返回 4xx TC-K05~TC-K08 ✅ 通过 验收通过
47 前后端联调 前端页面可访问且与后端联通 FR-051/FR-052 全部 HTTP 200,代理返回后端数据 TC-J01~TC-J05 ✅ 通过 验收通过
验收结论

功能验收共 47 项,通过 45 项,不通过 2 项,通过率 95.7%。 两处不通过分别对应缺陷 BUG-001(价格边界导致 500)与 BUG-002(搜索通配符未转义), 均不影响核心交易主流程。建议修复后回归复验,其余功能可判定为验收通过。

教师点评

(评审后填写)

⚠️ **GitHub.com Fallback** ⚠️