# 店铺设置 — 测试用例

> **依据：** 《店铺设置功能需求.md》v1.0、《店铺设置技术方案.md》v1.1  
> **关联：** 平台《店铺管理测试用例.md》SHP-API-033/034、《员工管理测试用例.md》EM-UT-005/EM-API-配额、《商家端店铺上下文接口说明》  
> **范围：** 商家端 `/agri/seller/shop/**`；`ShopServiceImpl`（商家资料/员工统计）、`SellerShopController`、`SellerShopContextSupport`  
> **排除：** 平台 `/agri/shopSetting` 全局策略 CRUD、员工 CRUD（见员工管理专册）、C 端会员  
> **环境：** RuoYi v3.9.2-springboot2；MySQL 5.7.39；请求头 **`X-Shop-Id`** + 商家 Token  
> **v1.1：** 同步已实现自动化：`ShopServiceImplTest`（资料 join/校验/员工统计）、`SellerShopControllerTest`（GET/PUT/employeeStats + 无 shopId 拒绝）

---

## 用例编号说明

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

> **命名区分：** 平台全局策略用例前缀 **SSS-**（《店铺设置测试用例.md》平台侧）；本模块 **SS-** 指 **商家端 · 店铺设置**。

---

## 测试数据约定

| 实体 | 说明 |
|------|------|
| 商户 A | 经营账号 `13800001001`；店铺 **101**（最早创建）、**102**；联系人：张三 / 13800138000；`max_sub_admin=5` |
| 商户 B | 经营账号 `13800002001`；店铺 **201**（用于越权） |
| 店铺 101 | 名称「张三农资店」；2 员工（1 正常 + 1 停用）；经营账号 **不计入** 员工统计 |
| 店铺 102 | 名称「张三分店」；0 员工 |
| 全局配额 | `biz_shop_global_config.max_sub_admin=5` |
| Token | 商户 A 经营账号；权限 `agri:seller:shop:query` + `edit`；`X-Shop-Id=101` |
| 只读 Token | 仅 `agri:seller:shop:query`，无 `edit` |
| 员工 Token | 商户 A 员工；绑定 shopId=101；角色含/不含店铺设置菜单 |

---

## 一、单元测试

### SS-UT-001 查询资料返回当前店 biz_shop 字段

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-001 |
| **测试模块** | 店铺设置 |
| **测试项** | selectSellerShopProfile |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 ST1：按 shopId 读当前店资料 |
| **前置条件** | `shopMapper.selectById(101)` 返回有效店；含 name/avatar/desc/phone/status/createTime |
| **测试步骤** | 调用 `selectSellerShopProfile(101L)` |
| **预期结果** | VO 中 shopId=101；字段与 `biz_shop` 一致；shopStatus 只读带回 |

### SS-UT-002 查询资料 join 商户联系人只读字段

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-002 |
| **测试模块** | 店铺设置 |
| **测试项** | selectSellerProfileById join |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 ST3：负责人/联系电话来自商户 |
| **前置条件** | join 查询返回 contactName=张三、contactPhone=13800138000、merchantName=张三农资 |
| **测试步骤** | 调用 `selectSellerShopProfile(101L)` |
| **预期结果** | VO 含 contactName、contactPhone、merchantName；**不可** 经 update 写入 |

### SS-UT-003 联系人未完善返回空

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-003 |
| **测试模块** | 店铺设置 |
| **测试项** | 联系人空值 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 §5.2：未完善不阻断查询 |
| **前置条件** | 商户 contact_name/contact_phone 为 null |
| **测试步骤** | 调用 `selectSellerShopProfile` |
| **预期结果** | contactName/contactPhone 为 null；**不抛异常** |

### SS-UT-004 更新资料四字段成功

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-004 |
| **测试模块** | 店铺设置 |
| **测试项** | updateSellerShopProfile 正向 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 ST2、ST5 |
| **前置条件** | 店存在；店名唯一 count=0；DTO 含 name/avatar/desc/phone |
| **测试步骤** | `updateSellerShopProfile(101L, dto, "seller")` |
| **预期结果** | 调用 `shopMapper.update` 一次；**仅** 写入四字段 + updateBy；**不** 改 shop_status/merchant_id |

### SS-UT-005 客服电话选填为空可保存

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-005 |
| **测试模块** | 店铺设置 |
| **测试项** | shopPhone 可空 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 §6.1 电话选填（对齐 SHP 商家电话规则） |
| **前置条件** | 有效 DTO；shopPhone=null 或 "" |
| **测试步骤** | 调用 update |
| **预期结果** | 保存成功；`shop_phone` 可为 null |

### SS-UT-006 店名为空拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-006 |
| **测试模块** | 店铺设置 |
| **测试项** | validateShopName 必填 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 §6.3 |
| **前置条件** | shopName 为空 |
| **测试步骤** | 调用 update |
| **预期结果** | 抛 ServiceException；msg 含「请输入店铺名称」；**不** update |

### SS-UT-007 头像为空拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-007 |
| **测试模块** | 店铺设置 |
| **测试项** | validateShopAvatar |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 §6.3 头像必填 |
| **前置条件** | shopAvatar 为空 |
| **测试步骤** | 调用 update |
| **预期结果** | msg「请上传店铺头像」；不 update |

### SS-UT-008 店名重复拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-008 |
| **测试模块** | 店铺设置 |
| **测试项** | countByShopName 唯一 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 ST4 |
| **前置条件** | 店 102 已占用名「张三分店」；当前改 101 为同名；count>0 |
| **测试步骤** | update shopId=101，shopName=张三分店 |
| **预期结果** | msg「店铺名称已存在」；不 update |

### SS-UT-009 店名不变允许保存（排除自身）

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-009 |
| **测试模块** | 店铺设置 |
| **测试项** | 唯一性排除当前店 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 ST4 边界 |
| **前置条件** | countByShopName(name, 101)=0（仅自身占用） |
| **测试步骤** | 仅改 desc，name 保持「张三农资店」 |
| **预期结果** | 保存成功 |

### SS-UT-010 电话格式非法拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-010 |
| **测试模块** | 店铺设置 |
| **测试项** | validateShopPhone |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 §6.3 电话格式 |
| **前置条件** | shopPhone=`abc` 或长度非法 |
| **测试步骤** | 调用 update |
| **预期结果** | msg「商家电话格式不正确」 |

### SS-UT-011 简介超长拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-011 |
| **测试模块** | 店铺设置 |
| **测试项** | shopDesc 长度 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 §6.3 ≤1000 |
| **前置条件** | shopDesc 长度 1001 |
| **测试步骤** | 调用 update |
| **预期结果** | msg「店铺描述过长」 |

### SS-UT-012 店铺不存在拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-012 |
| **测试模块** | 店铺设置 |
| **测试项** | requireShop |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 §6.3 当前店有效 |
| **前置条件** | selectById 返回 null 或 del_flag=2 |
| **测试步骤** | get/update shopId=999 |
| **预期结果** | msg「店铺不存在」 |

### SS-UT-013 员工统计含停用计入 total

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-013 |
| **测试模块** | 店铺设置 |
| **测试项** | countEmployeesByShopId |
| **测试类型** | 单元测试 / SQL |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 ST6、SS6 |
| **前置条件** | 店 101：2 员工（1 正常 status=0，1 停用 status=1） |
| **测试步骤** | 调用 `selectSellerEmployeeStats(101, merchantA)` |
| **预期结果** | totalCount=2；disabledCount=1 |

### SS-UT-014 员工统计不含经营账号

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-014 |
| **测试模块** | 店铺设置 |
| **测试项** | shop_id IS NOT NULL 过滤 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 ST7 |
| **前置条件** | 商户 A 有 1 经营账号 + 2 店 101 员工 |
| **测试步骤** | 统计 shopId=101 |
| **预期结果** | totalCount=2；**不含** shop_id=NULL 行 |

### SS-UT-015 员工统计按当前店隔离

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-015 |
| **测试模块** | 店铺设置 |
| **测试项** | 店铺维度统计 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 ST6 多店 |
| **前置条件** | 101 有 2 员工；102 有 0 员工 |
| **测试步骤** | 分别 stats(101)、stats(102) |
| **预期结果** | 101 total=2；102 total=0 |

### SS-UT-016 配额 usedCount 与 Facade maxCount

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-016 |
| **测试模块** | 店铺设置 |
| **测试项** | 商户级配额 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 + Mockito |
| **测试目的** | 验证 ST9、§7.3 |
| **前置条件** | 商户 A 全店员工合计 3；Facade.getMaxSubAdmin()=5 |
| **测试步骤** | 调用 selectSellerEmployeeStats |
| **预期结果** | usedCount=3；maxCount=5；**不** 写 global_config |

### SS-UT-017 assertShopAccessible 员工不可跨店

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-017 |
| **测试模块** | 店铺设置 |
| **测试项** | SellerShopContextSupport |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 ST1、§8.1 员工绑定店 |
| **前置条件** | 员工 account.shop_id=101 |
| **测试步骤** | assertShopAccessible(account, 102) |
| **预期结果** | 抛异常；msg 含店铺无效/不属于 |

### SS-UT-018 assertShopAccessible 经营账号可访问同商户任店

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UT-018 |
| **测试模块** | 店铺设置 |
| **测试项** | 经营账号多店 |
| **测试类型** | 单元测试 |
| **测试工具** | JUnit 5 |
| **测试目的** | 验证 §8.2 |
| **前置条件** | 经营账号 shop_id=null；102 属 merchant A |
| **测试步骤** | assertShopAccessible(account, 102) |
| **预期结果** | 通过，不抛异常 |

---

## 二、接口测试

### SS-API-001 GET 资料成功

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-001 |
| **测试模块** | 店铺设置 |
| **测试项** | GET /agri/seller/shop |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc / Apifox |
| **测试目的** | 验证 §5 展示主流程 |
| **前置条件** | Token + `X-Shop-Id: 101`；`agri:seller:shop:query` |
| **测试步骤** | `GET /agri/seller/shop`，Header 带 Authorization、X-Shop-Id |
| **预期结果** | HTTP 200；`code=200`；data 含 shopName、shopAvatar、shopDesc、shopPhone、shopStatus、createTime、contactName、contactPhone |

### SS-API-002 GET 资料与 MockMvc 委托 shopId

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-002 |
| **测试模块** | 店铺设置 |
| **测试项** | Controller getProfile |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc |
| **测试目的** | 验证 SellerShopContext 传参（对齐 SHP-API-033） |
| **前置条件** | SellerShopContext.setShopId(101) |
| **测试步骤** | MockMvc GET `/agri/seller/shop` |
| **预期结果** | 200；service.selectSellerShopProfile(101) 被调用 |

### SS-API-003 GET 无 query 权限拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-003 |
| **测试模块** | 店铺设置 |
| **测试项** | @PreAuthorize query |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §9 权限 |
| **前置条件** | Token **不含** `agri:seller:shop:query` |
| **测试步骤** | GET /agri/seller/shop |
| **预期结果** | HTTP 403 |

### SS-API-004 GET 跨商户店铺拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-004 |
| **测试模块** | 店铺设置 |
| **测试项** | 店铺归属校验 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 ST1 越权 |
| **前置条件** | 商户 A Token；`X-Shop-Id: 201`（商户 B 的店） |
| **测试步骤** | GET /agri/seller/shop |
| **预期结果** | `code=500` 或 403；msg 含店铺无效/不属于该商户 |

### SS-API-005 GET 员工账号访问绑定外店铺拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-005 |
| **测试模块** | 店铺设置 |
| **测试项** | 员工 X-Shop-Id 约束 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §8.1 员工不可切换店 |
| **前置条件** | 员工绑定 101；Header `X-Shop-Id: 102` |
| **测试步骤** | GET /agri/seller/shop |
| **预期结果** | 拒绝；msg 含店铺无效 |

### SS-API-006 PUT 更新资料成功

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-006 |
| **测试模块** | 店铺设置 |
| **测试项** | PUT /agri/seller/shop |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §6 编辑主流程 |
| **前置条件** | `agri:seller:shop:edit`；X-Shop-Id=101 |
| **测试步骤** | PUT body：`{"shopName":"张三农资旗舰店","shopAvatar":"/a.jpg","shopDesc":"新简介","shopPhone":"400-800-1234"}` |
| **预期结果** | `code=200`；msg 操作成功；再 GET 返回新值 |

### SS-API-007 PUT 成功后平台 list 同源（协作）

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-007 |
| **测试模块** | 店铺设置 |
| **测试项** | 与平台店铺列表同步 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 ST5（对齐 SHP-API-034） |
| **前置条件** | 商家 PUT 改 shopName；平台管理员 Token |
| **测试步骤** | 1. PUT 改名称 2. `GET /agri/shop/list` 检索该店 |
| **预期结果** | 平台列表 **立即** 展示新名称；**无** 同步任务延迟 |

### SS-API-008 PUT 无 edit 权限拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-008 |
| **测试模块** | 店铺设置 |
| **测试项** | @PreAuthorize edit |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §9 仅查询不可保存 |
| **前置条件** | 仅 query 权限 Token |
| **测试步骤** | PUT /agri/seller/shop |
| **预期结果** | HTTP 403 |

### SS-API-009 PUT 店名重复

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-009 |
| **测试模块** | 店铺设置 |
| **测试项** | 唯一性接口层 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 ST4 |
| **前置条件** | 102 已名「张三分店」 |
| **测试步骤** | PUT 101 的 shopName=张三分店 |
| **预期结果** | `code=500`；msg「店铺名称已存在」 |

### SS-API-010 PUT 电话格式错误

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-010 |
| **测试模块** | 店铺设置 |
| **测试项** | shopPhone 校验 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §12 |
| **前置条件** | shopPhone=`invalid` |
| **测试步骤** | PUT |
| **预期结果** | msg「商家电话格式不正确」 |

### SS-API-011 PUT 不传 shopPhone 成功

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-011 |
| **测试模块** | 店铺设置 |
| **测试项** | 电话选填 |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc |
| **测试目的** | 验证 SS-UT-005 接口层 |
| **前置条件** | 合法 name/avatar/desc；无 shopPhone |
| **测试步骤** | PUT |
| **预期结果** | 200；service.update 被调用 |

### SS-API-012 PUT 不修改 shop_status

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-012 |
| **测试模块** | 店铺设置 |
| **测试项** | 不可改字段 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox + DB 断言 |
| **测试目的** | 验证 §6.4、ST2 |
| **前置条件** | 店 101 shop_status=0（开业） |
| **测试步骤** | PUT 仅改名称；查库 biz_shop |
| **预期结果** | shop_status **仍为 0**；contact_name **不变** |

### SS-API-013 GET employeeStats 成功

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-013 |
| **测试模块** | 店铺设置 |
| **测试项** | GET /agri/seller/shop/employeeStats |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §7 员工概览 |
| **前置条件** | 店 101：2 员工 1 停用；商户 A 全店 used=3；max=5 |
| **测试步骤** | GET employeeStats，X-Shop-Id=101 |
| **预期结果** | totalCount=2；disabledCount=1；usedCount=3；maxCount=5；shopName 正确 |

### SS-API-014 employeeStats 与 employee/quota 一致

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-014 |
| **测试模块** | 店铺设置 |
| **测试项** | 配额协作 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §7.3、技术方案 §3.3 |
| **前置条件** | 同一 Token、X-Shop-Id |
| **测试步骤** | 依次 GET `/employeeStats` 与 `/agri/seller/employee/quota` |
| **预期结果** | usedCount、maxCount **相同** |

### SS-API-015 切换店铺后 stats 变化

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-015 |
| **测试模块** | 店铺设置 |
| **测试项** | 多店统计隔离 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 ST10、§8.2 |
| **前置条件** | 101 total=2；102 total=0 |
| **测试步骤** | 1. X-Shop-Id=101 GET stats 2. PUT context 切 102 3. X-Shop-Id=102 GET stats |
| **预期结果** | 第一次 total=2；第二次 total=0；资料 GET 亦变为店 102 |

### SS-API-016 GET employeeStats 无 query 权限拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-016 |
| **测试模块** | 店铺设置 |
| **测试项** | 统计接口权限 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 §9 |
| **前置条件** | Token 无 shop:query |
| **测试步骤** | GET employeeStats |
| **预期结果** | HTTP 403 |

### SS-API-017 未登录拒绝

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-017 |
| **测试模块** | 店铺设置 |
| **测试项** | 认证 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证安全基线 |
| **前置条件** | 无 Authorization |
| **测试步骤** | GET /agri/seller/shop |
| **预期结果** | HTTP 401 |

### SS-API-018 员工创建后 stats 刷新增加

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-018 |
| **测试模块** | 店铺设置 |
| **测试项** | 与员工管理协作 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 SS5 |
| **前置条件** | 店 101 total=2 |
| **测试步骤** | 1. POST 员工管理创建 1 人 2. GET employeeStats |
| **预期结果** | totalCount=3；usedCount +1 |

### SS-API-019 平台改 max_sub_admin 后 maxCount 只读更新

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-019 |
| **测试模块** | 店铺设置 |
| **测试项** | 全局配额消费 |
| **测试类型** | 接口测试 |
| **测试工具** | Apifox |
| **测试目的** | 验证 ST9；**非** 本模块改配置 |
| **前置条件** | 平台 PUT `/agri/shopSetting` maxSubAdmin=8 |
| **测试步骤** | 商家 GET employeeStats |
| **预期结果** | maxCount=8；商家 **无** PUT 改配额接口 |

### SS-API-020 MockMvc PUT 委托 Service

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-API-020 |
| **测试模块** | 店铺设置 |
| **测试项** | Controller updateProfile |
| **测试类型** | 接口测试 |
| **测试工具** | MockMvc |
| **测试目的** | 回归 SellerShopControllerTest |
| **前置条件** | SellerShopContext.setShopId(1) |
| **测试步骤** | PUT JSON DTO |
| **预期结果** | 200；updateSellerShopProfile(1, dto, "seller") 被调用 |

---

## 三、界面测试（Playwright）

> **通用前置：** Playwright 启动 **Chromium（Chrome 通道）**；商家端 URL 如 `http://localhost:80`；经营账号 `13800001001` / 测试密码；登录后调用 context 写入 `X-Shop-Id`；菜单 **店铺设置**（路由 `/agri/seller/shop` 或侧栏等价入口）。

### SS-UI-001 进入页面展示店铺资料与员工概览

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-001 |
| **测试模块** | 店铺设置 |
| **测试项** | 页面加载 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright (Chrome) |
| **测试目的** | 验证 §3、§5、§7 主展示 |
| **前置条件** | 经营账号已登录；当前店=张三农资店(101) |
| **测试步骤** | 1. `page.goto` 登录页并登录 2. 侧栏点击「店铺设置」 |
| **预期结果** | 页头展示当前店名；**店铺资料区** 含头像、名称、创建时间、简介、负责人、联系电话、客服电话；**员工概览** 含已有员工数、停用员工数及配额（如 3/5） |

### SS-UI-002 联系人字段只读不可编辑

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-002 |
| **测试模块** | 店铺设置 |
| **测试项** | 只读字段 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 ST3、§6.4 |
| **前置条件** | 已进入店铺设置 |
| **测试步骤** | 点「编辑」；检查负责人姓名、联系电话、创建时间、店铺状态 |
| **预期结果** | 上述字段 **不可编辑** 或 **不在** 编辑表单内；仅头像/名称/简介/客服电话可改 |

### SS-UI-003 编辑保存成功并刷新展示

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-003 |
| **测试模块** | 店铺设置 |
| **测试项** | 编辑保存 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §6.2 主流程 |
| **前置条件** | 有 edit 权限 |
| **测试步骤** | 1. 点「编辑」2. 改店铺名称、简介、客服电话 3. 点「保存」 |
| **预期结果** | 提示保存成功；展示态显示新值；**不** 刷新整页丢失登录态 |

### SS-UI-004 取消编辑不保存

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-004 |
| **测试模块** | 店铺设置 |
| **测试项** | 取消编辑 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §6.2 取消 |
| **前置条件** | 已进入编辑态 |
| **测试步骤** | 修改名称 → 点「取消」 |
| **预期结果** | 回到展示态；名称 **仍为** 修改前值 |

### SS-UI-005 店名为空前端拦截

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-005 |
| **测试模块** | 店铺设置 |
| **测试项** | 前端校验 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §6.3 |
| **前置条件** | 编辑态 |
| **测试步骤** | 清空店铺名称 → 保存 |
| **预期结果** | 表单校验提示；**不** 发起 PUT 或 PUT 失败提示 |

### SS-UI-006 客服电话格式错误提示

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-006 |
| **测试模块** | 店铺设置 |
| **测试项** | 电话校验 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §12 |
| **前置条件** | 编辑态 |
| **测试步骤** | 客服电话填 `abc` → 保存 |
| **预期结果** | 前端或后端提示格式错误；数据未更新 |

### SS-UI-007 仅 query 权限隐藏或禁用保存

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-007 |
| **测试模块** | 店铺设置 |
| **测试项** | 权限 UI |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §9 |
| **前置条件** | 员工角色 **仅** `agri:seller:shop:query` |
| **测试步骤** | 登录 → 进入店铺设置 |
| **预期结果** | 可查看资料与统计；**无**「编辑」或保存按钮不可用 |

### SS-UI-008 跳转员工管理

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-008 |
| **测试模块** | 店铺设置 |
| **测试项** | 员工概览入口 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §7.2 |
| **前置条件** | 有员工管理菜单权限 |
| **测试步骤** | 点击「前往员工管理」/等价链接 |
| **预期结果** | 路由至 `/agri/seller/employee`；列表 **仅** 当前店员工 |

### SS-UI-009 无员工管理权限时入口隐藏或禁用

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-009 |
| **测试模块** | 店铺设置 |
| **测试项** | 跳转权限 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §9 |
| **前置条件** | 有 shop:query；**无** employee:list |
| **测试步骤** | 进入店铺设置 |
| **预期结果** | 仍可看员工 **数字**；跳转员工管理入口 **隐藏或禁用** |

### SS-UI-010 切换店铺后资料与统计刷新

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-010 |
| **测试模块** | 店铺设置 |
| **测试项** | 多店切换 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 ST10、§8.2 |
| **前置条件** | 商户 A 有店 101、102；101 有员工、102 无 |
| **测试步骤** | 1. 当前 101 记录店名与员工数 2. 页头切换至 102 3. 观察本页 |
| **预期结果** | 店名变为「张三分店」；员工 total=0；**不** 残留 101 数据 |

### SS-UI-011 编辑店 102 不影响店 101 名称

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-011 |
| **测试模块** | 店铺设置 |
| **测试项** | 多店资料隔离 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §8.2 |
| **前置条件** | 已切换至店 102 |
| **测试步骤** | 编辑保存新名称 → 再切回 101 |
| **预期结果** | 101 名称 **不变**；102 为新名称 |

### SS-UI-012 员工管理增删后返回概览数字更新

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-012 |
| **测试模块** | 店铺设置 |
| **测试项** | 统计刷新 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 SS5 |
| **前置条件** | 店 101 total=2 |
| **测试步骤** | 1. 记录员工数 2. 进员工管理新建 1 人 3. 返回店铺设置 |
| **预期结果** | 已有员工数变为 3；配额 used 同步 +1 |

### SS-UI-013 联系人未完善显示占位

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-013 |
| **测试模块** | 店铺设置 |
| **测试项** | 空值展示 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 §5.2 |
| **前置条件** | 商户 contact 未填 |
| **测试步骤** | 进入店铺设置 |
| **预期结果** | 负责人/联系电话显示「—」或空；**仍可** 编辑店资料 |

### SS-UI-014 侧栏无菜单时不可访问

| 要素 | 内容 |
|------|------|
| **用例编号** | SS-UI-014 |
| **测试模块** | 店铺设置 |
| **测试项** | 菜单权限 |
| **测试类型** | 界面测试 |
| **测试工具** | Playwright |
| **测试目的** | 验证 SS3 |
| **前置条件** | 员工角色 **无** 店铺设置菜单 |
| **测试步骤** | 登录后查看侧栏；`page.goto('/agri/seller/shop')` |
| **预期结果** | 侧栏 **无** 入口；直链 403 或跳转无权限页 |

---

## 四、用例统计

| 类型 | 数量 | 编号段 |
|------|------|--------|
| 单元测试 | 18 | SS-UT-001～018 |
| 接口测试 | 20 | SS-API-001～020 |
| 界面测试 | 14 | SS-UI-001～014 |
| **合计** | **52** | — |

---

## 五、业务规则覆盖索引

| 规则 | 对应用例（示例） |
|------|------------------|
| ST1 当前店铺范围 | SS-UT-001/017/018，SS-API-004/005/015，SS-UI-010 |
| ST2 仅四字段可改 | SS-UT-004，SS-API-006/012，SS-UI-002/003 |
| ST3 联系人只读 | SS-UT-002/003，SS-API-001/012，SS-UI-002/013 |
| ST4 店名唯一 | SS-UT-008/009，SS-API-009，SS-UI-005 |
| ST5 平台 list 同源 | SS-UT-004，SS-API-007 |
| ST6 员工统计口径 | SS-UT-013/015，SS-API-013/015/018，SS-UI-001/012 |
| ST7 不含经营账号 | SS-UT-014，SS-API-013 |
| ST8 无员工 CRUD | SS-UI-008（跳转而非本页 CRUD） |
| ST9 配额只读 | SS-UT-016，SS-API-014/019 |
| ST10 切换刷新 | SS-API-015，SS-UI-010/011 |
| ST11 不校验会员 | （本模块无会员调用；回归由供给链其他用例覆盖） |
| SS1～SS6（功能需求） | SS-UI-001～012，SS-API-013～018 |

---

## 六、测试数据建议

| 数据 | 用途 |
|------|------|
| 商户 A 双店 101/102 | 多店切换、统计隔离 |
| 101 含正常+停用员工 | total/disabled 断言 |
| 占用全局店名「张三分店」 | 唯一性失败 |
| 联系人完整/未完善商户各一 | 只读展示 |
| 仅 query / 全权限 / 无菜单 三种角色 | 权限 UI/API |
| 平台改 max_sub_admin 后 | SS-API-019 |

---

## 七、自动化映射

| 用例 | 代码位置 |
|------|----------|
| SS-UT-001～003 | `ShopServiceImplTest.selectSellerShopProfile_joinMerchantAndMaskContactPhone` |
| SS-UT-004/005 | `ShopServiceImplTest.updateSellerShopProfile_withoutPhone_allowed` |
| SS-UT-006～012 | `ShopServiceImplTest.updateSellerShopProfile_duplicateName_rejected` / `invalidPhone_rejected` / `descTooLong_rejected`；`selectSellerShopProfile_joinMissing_rejected` |
| SS-UT-013～016 | `ShopServiceImplTest.selectSellerEmployeeStats_returnsShopAndQuotaCounts` / `selectSellerEmployeeStats_defaultMaxWhenFacadeNull` |
| SS-API-001～003 | `SellerShopControllerTest.getProfile_returnsShopFields` / `getProfile_withoutShopId_rejected` |
| SS-API-004～006 | `SellerShopControllerTest.updateProfile_delegatesToService` / `updateProfile_withoutShopId_rejected` |
| SS-API-017～020 | `SellerShopControllerTest.employeeStats_returnsCounts` / `employeeStats_withoutShopId_rejected` |
| SS-UI-* | 待前端落地后 `e2e/seller/shop-setting.spec.ts`（Playwright） |

**测试类路径：** `baqing-shop/src/test/java/com/ruoyi/web/modules/store/service/ShopServiceImplTest.java`、`.../controller/SellerShopControllerTest.java`

---

## 八、修订记录

| 版本 | 说明 |
|------|------|
| **v1.0** | 首版；52 用例（SS-UT / SS-API / SS-UI） |
| **v1.1** | 同步后端自动化映射；标注已实现单测/接口测方法名 |

---

*文档版本：v1.1 · 关联《店铺设置功能需求.md》v1.0、《店铺设置技术方案.md》v1.1*
