# 商品分类 — 测试用例（C 端）

> **依据：** 《商品分类功能需求.md》v1.0.1、《商品分类技术方案.md》v1.0  
> **关联：** 平台《商品分类测试用例.md》CAT-UT-013/014（同源 `isCategoryVisible`）、C 端《商城首页测试用例.md》MHP-UI-008/009（HM7 入口）、《关联需求分析.md》§11  
> **范围：** C 端 `/api/category/tree`、`/api/category/{level1Id}/level2-tabs`、`/api/category/goods`；`CategoryAppServiceImpl` / `CategoryAppController`  
> **代码落位：** `baqing-shop/src/main/java/com/ruoyi/web/modules/home/`  
> **排除：** 搜索执行与结果页、商品详情可购四条件校验、平台/店铺分类 CRUD、店铺商品分类 C 端导航、聚合 `/api/category/index`  
> **环境：** RuoYi v3.9.2-springboot2；MySQL 5.7.39；C 端 **无需 Token**（`@Anonymous`）；UI 使用 Playwright **`channel: 'chrome'`**

---

## 用例编号说明

| 前缀 | 类型 | 工具 |
|------|------|------|
| CGC-UT-xxx | 单元测试 | JUnit 5 + Mockito |
| CGC-API-xxx | 接口测试 | MockMvc / Apifox |
| CGC-UI-xxx | 界面测试 | Playwright（Google Chrome） |

> **命名：** **CGC** = Consumer Goods Category（C 端商品分类）；与平台 **CAT-** 区分。

---

## 测试数据约定

| 实体 | 说明 |
|------|------|
| 平台一级 | L1-A「兽药」show=1 sort=0；L1-B「饲料」show=1 sort=1；L1-H **隐藏** show=0；L1-E **空壳**（无可见二级）；L1-S 店铺101一级（**不应出现**） |
| 平台二级 | L1-A 下 L2-A1「抗生素」、L2-A2「驱虫药」show=1；L2-H **隐藏** show=0；L2-P 父级 L1-H（**不可见**） |
| 店铺 | S101 开业；S102 **停业**；S103 已删 |
| 出售中商品 | G-A1@L2-A1 销量100 价88；G-A2 销量100 价99（同销量测排序）；G-A3 销量50；G-B1@S102 停业；G-Z1 stock=0；G-O1 已下架/待审核（**不进列表**） |
| 会员 | M1 正常；M2 **禁用**（分类仍可读） |

---

## 一、单元测试

### CGC-UT-001 分类树委托平台 Facade

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-001 |
| **测试模块** | C 端商品分类 |
| **测试项** | listCategoryTree |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 GC1、GC6 |
| **前置条件** | Mock `ICategoryFacade.listVisibleByShopId(null)` 返回含 L1-A 树 |
| **测试步骤** | 调用 `listCategoryTree()` |
| **预期结果** | 调用 `listVisibleByShopId(null)`；返回与 Facade 一致 |

### CGC-UT-002 分类树空列表

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-002 |
| **测试模块** | C 端商品分类 |
| **测试项** | listCategoryTree 空态 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 §5.3 边界 |
| **前置条件** | Facade 返回 empty |
| **测试步骤** | `listCategoryTree()` |
| **预期结果** | 空 List；**不** 抛异常 |

### CGC-UT-003 二级 Tab 一级可见时返回

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-003 |
| **测试模块** | C 端商品分类 |
| **测试项** | listLevel2Tabs |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 GC5、GC7 |
| **前置条件** | L1-A 一级 show=1；Mapper 返回 L2-A1、L2-A2 |
| **测试步骤** | `listLevel2Tabs(L1-A.id)` |
| **预期结果** | 返回 2 条二级；顺序与 Mapper 一致 |

### CGC-UT-004 二级 Tab 一级隐藏拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-004 |
| **测试模块** | C 端商品分类 |
| **测试项** | listLevel2Tabs 校验 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 GC6 |
| **前置条件** | L1-H show=0 |
| **测试步骤** | `listLevel2Tabs(L1-H.id)` |
| **预期结果** | 抛 `ServiceException`；msg 含「不可见」或「不存在」 |

### CGC-UT-005 商品列表缺 categoryId

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-005 |
| **测试模块** | C 端商品分类 |
| **测试项** | listCategoryGoods 必填 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 §3.4 校验 |
| **前置条件** | query.categoryId 为空 |
| **测试步骤** | `listCategoryGoods(query)` |
| **预期结果** | 抛 `ServiceException`；「请选择商品分类」类提示 |

### CGC-UT-006 商品列表分类不可见拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-006 |
| **测试模块** | C 端商品分类 |
| **测试项** | isCategoryVisible |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 GC6 |
| **前置条件** | `isCategoryVisible(L2-H)=false` |
| **测试步骤** | `listCategoryGoods({categoryId:L2-H})` |
| **预期结果** | 抛 `ServiceException`；「分类不存在或不可见」 |

### CGC-UT-007 商品列表默认销量降序

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-007 |
| **测试模块** | C 端商品分类 |
| **测试项** | sortBy 默认 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 GC9 |
| **前置条件** | L2-A1 可见；sortBy 未传 |
| **测试步骤** | `listCategoryGoods(query)` |
| **预期结果** | Mapper 调用 `sortBy=sales_desc` |

### CGC-UT-008 商品列表价格升序排序

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-008 |
| **测试模块** | C 端商品分类 |
| **测试项** | sortBy price_asc |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 GC9 |
| **前置条件** | query.sortBy=`price_asc` |
| **测试步骤** | `listCategoryGoods(query)` |
| **预期结果** | Mapper 入参 `price_asc` |

### CGC-UT-009 非法 sortBy 拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-009 |
| **测试模块** | C 端商品分类 |
| **测试项** | sortBy 校验 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 §3.4 |
| **前置条件** | sortBy=`invalid`；分类可见 |
| **测试步骤** | `listCategoryGoods(query)` |
| **预期结果** | 抛 `ServiceException`；「排序参数无效」 |

### CGC-UT-010 商品列表透传 Mapper 顺序

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-010 |
| **测试模块** | C 端商品分类 |
| **测试项** | 列表顺序 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 GC8 |
| **前置条件** | Mapper 返回 G-A1 在 G-A3 前 |
| **测试步骤** | `listCategoryGoods(query)` |
| **预期结果** | 结果顺序与 Mapper 一致 |

### CGC-UT-011 商品列表零条

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-011 |
| **测试模块** | C 端商品分类 |
| **测试项** | 列表空态 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 §7.4 |
| **前置条件** | Mapper 返回 empty |
| **测试步骤** | `listCategoryGoods(query)` |
| **预期结果** | 空 List |

### CGC-UT-012 Facade null 树返回空

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UT-012 |
| **测试模块** | C 端商品分类 |
| **测试项** | listCategoryTree null |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证健壮性 |
| **前置条件** | Facade 返回 null |
| **测试步骤** | `listCategoryTree()` |
| **预期结果** | 空 List；**不** NPE |

---

## 二、接口测试

### CGC-API-001 分类树无需 Token

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-001 |
| **测试模块** | C 端商品分类 |
| **测试项** | GET /tree 匿名 |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc / Apifox |
| **测试目的** | 验证 GC2 |
| **前置条件** | 不传 Authorization |
| **测试步骤** | GET `/api/category/tree` |
| **预期结果** | `code=200`；`data` 为数组 |

### CGC-API-002 分类树含 children 契约

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-002 |
| **测试模块** | C 端商品分类 |
| **测试项** | tree VO |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc |
| **测试目的** | 验证 §3.2 |
| **前置条件** | 存在 L1-A 含 L2-A1 |
| **测试步骤** | GET `/tree` |
| **预期结果** | 含 `categoryId/categoryName/children`；child 含 `categoryId/categoryName` |

### CGC-API-003 分类树不含 show=0 一级

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-003 |
| **测试模块** | C 端商品分类 |
| **测试项** | tree 过滤 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC6 |
| **前置条件** | 库中 L1-H show=0 |
| **测试步骤** | GET `/tree` |
| **预期结果** | **不含** L1-H |

### CGC-API-004 分类树不含空壳一级

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-004 |
| **测试模块** | C 端商品分类 |
| **测试项** | 空壳一级 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC6、§4.2 |
| **前置条件** | L1-E show=1 但无可见二级 |
| **测试步骤** | GET `/tree` |
| **预期结果** | **不含** L1-E |

### CGC-API-005 分类树不含店铺分类

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-005 |
| **测试模块** | C 端商品分类 |
| **测试项** | 平台隔离 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC1 |
| **前置条件** | 存在 L1-S（shop_id=101） |
| **测试步骤** | GET `/tree` |
| **预期结果** | **不含** L1-S |

### CGC-API-006 二级 Tab 正常返回

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-006 |
| **测试模块** | C 端商品分类 |
| **测试项** | GET level2-tabs |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc |
| **测试目的** | 验证 GC5 |
| **前置条件** | L1-A 可见；下有 L2-A1、L2-A2 |
| **测试步骤** | GET `/api/category/{L1-A}/level2-tabs` |
| **预期结果** | `code=200`；`data.length=2` |

### CGC-API-007 二级 Tab 排序升序

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-007 |
| **测试模块** | C 端商品分类 |
| **测试项** | Tab sort_no |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC7 |
| **前置条件** | L2-A1 sort=0；L2-A2 sort=1 |
| **测试步骤** | GET level2-tabs |
| **预期结果** | 第一条 `categoryId=L2-A1` |

### CGC-API-008 二级 Tab 一级不存在

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-008 |
| **测试模块** | C 端商品分类 |
| **测试项** | level1 校验 |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc |
| **测试目的** | 验证 §3.3 |
| **前置条件** | level1Id=99999 |
| **测试步骤** | GET `/api/category/99999/level2-tabs` |
| **预期结果** | 业务失败；提示分类不存在/不可见 |

### CGC-API-009 二级 Tab 一级隐藏

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-009 |
| **测试模块** | C 端商品分类 |
| **测试项** | level1 show=0 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC6 |
| **前置条件** | L1-H show=0 |
| **测试步骤** | GET `/api/category/{L1-H}/level2-tabs` |
| **预期结果** | 业务失败 |

### CGC-API-010 商品列表分页成功

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-010 |
| **测试模块** | C 端商品分类 |
| **测试项** | GET /goods |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc |
| **测试目的** | 验证 §3.4 |
| **前置条件** | L2-A1 可见；≥1 出售中商品 |
| **测试步骤** | GET `/api/category/goods?categoryId=&pageNum=1&pageSize=10` |
| **预期结果** | `code=200`；含 `rows`、`total` |

### CGC-API-011 商品列表字段契约

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-011 |
| **测试模块** | C 端商品分类 |
| **测试项** | goods VO |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc |
| **测试目的** | 验证 GC10 |
| **前置条件** | G-A1 出售中 |
| **测试步骤** | GET `/goods?categoryId=L2-A1` |
| **预期结果** | row 含 `goodsId/goodsName/mainPic/salePrice/shopId/shopName` |

### CGC-API-012 商品列表缺 categoryId

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-012 |
| **测试模块** | C 端商品分类 |
| **测试项** | categoryId 必填 |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc |
| **测试目的** | 验证 §3.4 |
| **前置条件** | — |
| **测试步骤** | GET `/api/category/goods` |
| **预期结果** | 业务失败 |

### CGC-API-013 商品列表分类不可见

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-013 |
| **测试模块** | C 端商品分类 |
| **测试项** | 隐藏二级 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC6 |
| **前置条件** | L2-H show=0 |
| **测试步骤** | GET `/goods?categoryId=L2-H` |
| **预期结果** | 业务失败；「分类不存在或不可见」 |

### CGC-API-014 商品列表默认销量降序

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-014 |
| **测试模块** | C 端商品分类 |
| **测试项** | 默认排序 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC9 |
| **前置条件** | G-A1 销量100；G-A3 销量50 |
| **测试步骤** | GET `/goods?categoryId=L2-A1`（无 sortBy） |
| **预期结果** | 首条 `goodsId=G-A1` |

### CGC-API-015 商品列表价格升序

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-015 |
| **测试模块** | C 端商品分类 |
| **测试项** | sortBy price_asc |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC9 |
| **前置条件** | G-A1 价88；G-A2 价99 |
| **测试步骤** | GET `/goods?categoryId=L2-A1&sortBy=price_asc` |
| **预期结果** | 首条价 **更低** 的商品 |

### CGC-API-016 商品列表非法 sortBy

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-016 |
| **测试模块** | C 端商品分类 |
| **测试项** | sortBy 校验 |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc |
| **测试目的** | 验证 §3.4 |
| **前置条件** | L2-A1 可见 |
| **测试步骤** | GET `/goods?categoryId=L2-A1&sortBy=foo` |
| **预期结果** | 业务失败；「排序参数无效」 |

### CGC-API-017 商品列表仅出售中

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-017 |
| **测试模块** | C 端商品分类 |
| **测试项** | goods_status |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC8 |
| **前置条件** | G-O1 已下架同分类 |
| **测试步骤** | GET `/goods?categoryId=L2-A1` |
| **预期结果** | **不含** G-O1 |

### CGC-API-018 商品列表含停业店商品

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-018 |
| **测试模块** | C 端商品分类 |
| **测试项** | 浏览层店态 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC13 |
| **前置条件** | G-B1@S102 停业、出售中 |
| **测试步骤** | GET `/goods?categoryId=对应二级` |
| **预期结果** | **含** G-B1 |

### CGC-API-019 禁用会员仍可读

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-019 |
| **测试模块** | C 端商品分类 |
| **测试项** | 会员禁用 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 GC2 |
| **前置条件** | M2 禁用 Token |
| **测试步骤** | 带 Token 调 `/tree`、`/goods` |
| **预期结果** | 均 `code=200` |

### CGC-API-020 平台改 show 后 goods 拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-API-020 |
| **测试模块** | C 端商品分类 |
| **测试项** | 分类联动 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §10 |
| **前置条件** | 平台将 L2-A1 show 改为 0 |
| **测试步骤** | GET `/goods?categoryId=L2-A1` |
| **预期结果** | 业务失败 |

---

## 三、界面测试（Playwright · Chrome）

> **路由建议：** A `/#/mall/category/all`；B `/#/mall/category/l1/{id}`；C `/#/mall/category/goods?categoryId=`（以实际为准）

### CGC-UI-001 首页点一级进 B 页

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-001 |
| **测试模块** | C 端商品分类 |
| **测试项** | HM7 入口 B |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC5、HM7 |
| **前置条件** | 首页已加载；存在 L1-A |
| **测试步骤** | 点击首页一级「兽药」 |
| **预期结果** | 进入 B 页；可见二级 Tab 与商品列表区 |

### CGC-UI-002 首页点更多进 A 页

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-002 |
| **测试模块** | C 端商品分类 |
| **测试项** | HM7 入口 A |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC4 |
| **前置条件** | 首页已加载 |
| **测试步骤** | 点击类目区「更多」 |
| **预期结果** | 进入 A 全部分类页；左右分栏可见 |

### CGC-UI-003 A 页左切一级联动右侧

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-003 |
| **测试模块** | C 端商品分类 |
| **测试项** | A 页联动 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC4、§5.1 |
| **前置条件** | A 页已打开；有 L1-A、L1-B |
| **测试步骤** | 点击左侧 L1-B |
| **预期结果** | 右侧刷新为 L1-B 下二级列表；**不跳转** 新页 |

### CGC-UI-004 A 页点二级进 C 独立页

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-004 |
| **测试模块** | C 端商品分类 |
| **测试项** | A1 跳转 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC4、GC5a |
| **前置条件** | A 页右侧有 L2-A1 |
| **测试步骤** | 点击「抗生素」 |
| **预期结果** | 进入 **C 独立列表页**；**无** Tab；可见路径「兽药 > 抗生素」 |

### CGC-UI-005 B 页默认选中首 Tab

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-005 |
| **测试模块** | C 端商品分类 |
| **测试项** | 默认 Tab |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 §6.1 |
| **前置条件** | 从首页进入 L1-A |
| **测试步骤** | 观察 Tab 与列表 |
| **预期结果** | **排序最靠前** 的二级 Tab 高亮；列表对应该 Tab |

### CGC-UI-006 B 页切换 Tab 列表回顶

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-006 |
| **测试模块** | C 端商品分类 |
| **测试项** | C1 回顶 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC5、C1 |
| **前置条件** | B 页列表已下滚 |
| **测试步骤** | 点击另一二级 Tab |
| **预期结果** | 列表 **回顶**；展示新 Tab 商品 |

### CGC-UI-007 搜索栏占位文案

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-007 |
| **测试模块** | C 端商品分类 |
| **测试项** | 搜索占位 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC3 |
| **前置条件** | 打开 A 或 B 或 C 页 |
| **测试步骤** | 读取搜索框 placeholder |
| **预期结果** | **「搜索兽药、饲料、店铺」** |

### CGC-UI-008 点击搜索栏进搜索页

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-008 |
| **测试模块** | C 端商品分类 |
| **测试项** | 搜索入口 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC-S1 |
| **前置条件** | 分类页已加载 |
| **测试步骤** | 点击搜索栏 |
| **预期结果** | 路由至搜索输入页 |

### CGC-UI-009 C 页含搜索栏无 Tab

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-009 |
| **测试模块** | C 端商品分类 |
| **测试项** | C 页结构 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC5a |
| **前置条件** | 从 A 进入 C 页 |
| **测试步骤** | 检查页顶结构 |
| **预期结果** | 有搜索栏+路径标题；**无** 二级 Tab |

### CGC-UI-010 商品卡片字段展示

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-010 |
| **测试模块** | C 端商品分类 |
| **测试项** | 列表卡片 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC10 |
| **前置条件** | 列表有 G-A1 |
| **测试步骤** | 检查首卡 |
| **预期结果** | 可见主图、名称、售价、店铺名；**不** 展示销量数字 |

### CGC-UI-011 切换销量价格排序

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-011 |
| **测试模块** | C 端商品分类 |
| **测试项** | 排序 UI |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC9、§7.3 |
| **前置条件** | 列表 ≥2 条不同价/销量 |
| **测试步骤** | ① 选「价格升序」② 选「销量降序」 |
| **预期结果** | 列表顺序 **随之变化** |

### CGC-UI-012 点击商品进详情

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-012 |
| **测试模块** | C 端商品分类 |
| **测试项** | 进详情 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC11 |
| **前置条件** | 列表有商品 |
| **测试步骤** | 点击商品卡片 |
| **预期结果** | 进入商品详情；URL 含 `goodsId` |

### CGC-UI-013 访客与会员均可浏览

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-013 |
| **测试模块** | C 端商品分类 |
| **测试项** | 访客/会员 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC2 |
| **前置条件** | ① 未登录 ② M1 登录 |
| **测试步骤** | 分别打开 A/B 页 |
| **预期结果** | 均可见分类与列表 |

### CGC-UI-014 零商品空态

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-014 |
| **测试模块** | C 端商品分类 |
| **测试项** | 列表空态 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 §7.4 |
| **前置条件** | 某二级无出售中商品 |
| **测试步骤** | 打开该二级列表 |
| **预期结果** | 空态文案（如「该分类下暂无商品」） |

### CGC-UI-015 分类树失败不白屏

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-015 |
| **测试模块** | C 端商品分类 |
| **测试项** | tree 失败 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC14 |
| **前置条件** | Mock `/tree` 500 |
| **测试步骤** | 打开 A 页 |
| **预期结果** | 空态/错误提示；**不** 整页白屏 |

### CGC-UI-016 商品列表失败空态

| 要素 | 内容 |
|------|------|
| **用例编号** | CGC-UI-016 |
| **测试模块** | C 端商品分类 |
| **测试项** | goods 失败 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright（Chrome） |
| **测试目的** | 验证 GC14、§7.6 |
| **前置条件** | Mock `/goods` 失败；Tab 仍可见 |
| **测试步骤** | 打开 B 页 |
| **预期结果** | 列表区空态；Tab 区 **仍展示** |

---

## 四、业务规则覆盖矩阵

| 规则 | UT | API | UI |
|------|:--:|:---:|:--:|
| GC1 仅平台分类 | — | API-005 | — |
| GC2 匿名可读 | — | API-001/019 | UI-013 |
| GC3 搜索占位 | — | — | UI-007 |
| GC4 A 页/A→C | UT-003 | API-002 | UI-002/003/004 |
| GC5 B Tab+列表 | UT-003 | API-006/007 | UI-001/005/006 |
| GC5a C 独立页 | — | — | UI-004/009 |
| GC6 可见性 | UT-004/006 | API-003/004/008/009/013/020 | — |
| GC7 排序 | — | API-007 | — |
| GC8 出售中 | UT-010 | API-017 | — |
| GC9 四档排序 | UT-007/008/009 | API-014/015/016 | UI-011 |
| GC10 卡片字段 | — | API-011 | UI-010 |
| GC11 进详情 | — | — | UI-012 |
| GC12 展示≠可购 | — | — | — |
| GC13 停业/零库存 | — | API-018 | — |
| GC14 模块空态 | UT-011/012 | — | UI-015/016 |
| GC15 无写接口 | — | — | — |

---

## 五、自动化映射

| 用例 | 建议代码位置 |
|------|--------------|
| CGC-UT-001～012 | `CategoryAppServiceImplTest.java` |
| CGC-API-001～020 | `CategoryAppControllerTest.java` |
| CGC-UI-001～016 | `e2e/consumer/category.spec.ts`（Playwright `channel: 'chrome'`） |

---

## 六、用例统计

| 类型 | 数量 |
|------|------|
| 单元测试 CGC-UT | 12 |
| 接口测试 CGC-API | 20 |
| 界面测试 CGC-UI | 16 |
| **合计** | **48** |

---

## 七、修订记录

| 版本 | 说明 |
|------|------|
| **v1.0** | 首版；48 用例；覆盖 GC1～GC15、A/B/C 三页、四档排序、HM7 入口 |

---

*文档版本：v1.0 · 关联《商品分类功能需求.md》v1.0.1、《商品分类技术方案.md》v1.0*
