# 养殖产业数据 — 测试用例 > 依据:`养殖产业数据功能需求.md`、`养殖产业数据技术方案.md`、`养殖产业数据前端技术方案.md` > **接口 Base Path**:`/dataModel/breedingIndustry`(含网关/context-path 时须补齐前缀)。鉴权:若依 Cookie / `Authorization` Token。 **通用前置**:已执行 `sql/biz_pasture.sql`、`sql/biz_grassland.sql`、`sql/biz_yak_asset.sql`、`sql/biz_yak_disease_warning.sql`、`sql/biz_yak_herd_inventory.sql`、`sql/biz_yak_outbound_report.sql`;测试账号具备 `dataModel:breedingIndustry:query` 及菜单「养殖产业数据」。 **UI 工具**:**Playwright** + **Chromium**,`channel: 'chrome'`(本机 **Google Chrome**)。组件路径:`livestockIndustry/breedingIndustry/index`。 --- ## 测试数据样本(可替换为环境真实 ID) | 代号 | 说明 | | --- | --- | | **UA** | 仅可见牧场 **P1**(`id=101`) | | **UB** | 仅可见 **P2**(`id=202`) | | **ADMIN** | 县级全量,可见 P1+P2 | | **U0** | 有模块权限但可见牧场 **[]** | | **P-停** | `biz_status=2` 停业牧场,UA 不可见或全量不计入牧场数 | | **Y-N** | P1、`asset_status=1`、`del_flag=0` | | **Y-死/丢/栏** | `status` 2/3/4,不计当前存栏 | | **Y-U** | `gender` 空,计入总量不计公母 | | **Y-O** | `status=4`,`status_change_date` 在当年且 ≤ 统计日 | | **Y-O0** | `status=4`,`status_change_date` 空 | | **Y-P0** | `pasture_id` 空 | | **Y-H** | `status=4`,`change_date` 在 3 月;2 月末趋势仍计入 | | **Y-L** | `status=4`,`change_date` = 2 月最后一天;2 月末 **不计** | | **W-in** | 当年 1/1 0:00 ≤ `alert_time` ≤ 统计日 23:59:59 | | **W-out** | `alert_time` 为上年或统计日次日 | | **G** | 草场 `del_flag=0`;退化 1~5、禁牧/轮牧/全年各造 1 条 | | **HERD-L** | `biz_yak_herd_inventory` 最近填报年月全县 bull/cow/yak 合计 | | **HERD-M** | 某历史月填报记录,用于滚动 12 月趋势 | **联调统计日**:固定 **2026-05-20**(`monthlyTrend` 为所选年 1~N;每项含 `statYear`、`month`、`bullCount`、`cowCount`)。 --- ## 覆盖说明 | 类别 | 覆盖要点 | | --- | --- | | **正常流程** | 菜单进入自动加载、刷新全页、四块指标与图表展示(§4.2、§5.1~§5.5) | | **异常流程** | 未登录、无权限、聚合失败、空库、接口不存在维护能力(§3、§7.2、技术§3.1.8) | | **业务约束** | §2.5~§2.11 口径;§2.9 权限三态;§3 本期不实现项(无 CRUD/筛选/导出) | --- ## 一、单元测试用例 | 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | ZCZX-YZCYSJ-UT-001 | 数据权限 | 全量可见牧场 ID 列表 | 单元测试 | JUnit5 | §2.6、§2.9 | Mock ADMIN 数据范围 | 调用 `BreedingIndustryPastureScope.resolve()` | 返回全部 `biz_status=1` 且未删牧场 ID;非 null 非空 | | ZCZX-YZCYSJ-UT-002 | 数据权限 | 可见牧场为空列表 | 单元测试 | JUnit5 | §2.6 空 `[]` | Mock U0 | `loadDashboard([])` | 填报三项仍返回;预警/图表=0;草场仍统计 | | ZCZX-YZCYSJ-UT-003 | 数据权限 | 部分牧场 IN 过滤 | 单元测试 | JUnit5 | §2.9 | 造数 P1、P2 | `allowed=[101]` 统计牦牛 | 仅 P1 档案计入 | | ZCZX-YZCYSJ-UT-004 | 存栏 | 仅正常状态 | 单元测试 | JUnit5 | §2.3 | 含 status 1/2/3/4 | `countInventory` | 仅 `asset_status=1` | | ZCZX-YZCYSJ-UT-005 | 存栏 | 逻辑删除排除 | 单元测试 | JUnit5 | §2.3 | `del_flag=2` 档案 | 统计 | 不计入 | | ZCZX-YZCYSJ-UT-006 | 存栏 | pasture_id 空排除 | 单元测试 | JUnit5 | §2.9 | Y-P0 | 统计 | 不计入任何牦牛类指标 | | ZCZX-YZCYSJ-UT-007 | 出栏 | 当年且变更日非空 | 单元测试 | JUnit5 | §2.4 | Y-O、Y-O0 | `countAnnualOutbound` | 仅 Y-O;Y-O0 为 0 | | ZCZX-YZCYSJ-UT-008 | 出栏 | 周期上界统计日 | 单元测试 | JUnit5 | §2.4 | `change_date=统计日` | 统计 | 计入;次日不计 | | ZCZX-YZCYSJ-UT-009 | 预警 | 去重 yak_no | 单元测试 | JUnit5 | §2.5 | 同牛 2 条 W-in | `countWarning` | 计 1 | | ZCZX-YZCYSJ-UT-010 | 预警 | 周期下界 1/1 0:00 | 单元测试 | JUnit5 | §2.5 | `alert_time=当年1/1 00:00:00` | 统计 | 计入 | | ZCZX-YZCYSJ-UT-011 | 预警 | 周期外排除 | 单元测试 | JUnit5 | §2.5 | W-out | 统计 | 0 | | ZCZX-YZCYSJ-UT-012 | 预警 | 须关联纳入档案 | 单元测试 | JUnit5 | §2.9 | 预警牛仅 P2、范围 P1 | `countWarning` | 0 | | ZCZX-YZCYSJ-UT-013 | 存栏变动 | 公母来自所选年最大月 | 单元测试 | JUnit5 | §5.3.1、§2.11 | HERD-L | `loadDashboard` | `bullCount`/`cowCount` 与所选年最大月一致;`unknownGenderCount=yak−公−母` | | ZCZX-YZCYSJ-UT-028 | 产业总览 | 填报三项所选年最大月 | 单元测试 | JUnit5 | §5.2、§2.11 | Mock 填报合计 | `loadDashboard` | `inventoryTotal`/`annualOutbound`/`pastureCount`/`grasslandAreaMu` 与大屏所选年口径一致 | | ZCZX-YZCYSJ-UT-014 | 性别 | trim 后匹配 | 单元测试 | JUnit5 | 技术§4 | `gender=' 母 '` | `normalizeGender` | 计母牛(档案类,预警用) | | ZCZX-YZCYSJ-UT-015 | 存栏结构 | 三类编码 | 单元测试 | JUnit5 | §5.4 | Mock 填报结构 | `buildYakInventoryStructure` | `categoryCode` 为 BULL/COW/INSURED | | ZCZX-YZCYSJ-UT-016 | 存栏结构 | 占比与零分母 | 单元测试 | JUnit5 | §5.4 | 合计 0 | `buildYakInventoryStructure` | 三类 count=0、ratio=0 仍返回 | | ZCZX-YZCYSJ-UT-017 | 存栏结构 | 细分明细 | 单元测试 | JUnit5 | §5.4 | 有细分数据 | details | 含种公牛/阉畜/幼畜/成畜/保险 | | ZCZX-YZCYSJ-UT-018 | 存栏趋势 | 所选年 1~N 长度 | 单元测试 | JUnit5 | §5.3.2、§2.11 | 最大填报月=7 | `buildBullCowMonthlyTrendFromHerdReport` | 长度=**7**;含 statYear+month | | ZCZX-YZCYSJ-UT-019 | 存栏趋势 | 缺月补零 | 单元测试 | JUnit5 | §2.11 | 仅 HERD-M 有数 | 趋势某月 | `bullCount`/`cowCount` 无填报为 **0** | | ZCZX-YZCYSJ-UT-020 | 存栏趋势 | 最大月与 header 一致 | 单元测试 | JUnit5 | §5.3.1 | HERD-L | 趋势最后一点 vs header | 公/母分别相等 | | ZCZX-YZCYSJ-UT-021 | 存栏趋势 | 无填报为空 | 单元测试 | JUnit5 | §2.11 | 所选年无存栏 | 趋势 | 空数组 | | ZCZX-YZCYSJ-UT-022 | 存栏趋势 | 不依赖档案月末 | 单元测试 | JUnit5 | §2.11 | 档案与填报不一致 | 趋势 | 以填报表为准 | | ZCZX-YZCYSJ-UT-023 | 牧场 | 原口径暂保留 | 单元测试 | JUnit5 | §2.6 | P-停、注销 | `countPastureInScope` 仍调用 | 结果**不**写入 `pastureCount` | | ZCZX-YZCYSJ-UT-024 | 草场 | 面积空不参与求和 | 单元测试 | JUnit5 | §2.6 | 一条 `area_mu` null | `sumArea` | 不计该条 | | ZCZX-YZCYSJ-UT-025 | 草场 | 可用=未退化+轻度 | 单元测试 | JUnit5 | §2.7 | 退化 1、2、3 各 1 | `availableCount` | 2 | | ZCZX-YZCYSJ-UT-026 | 草场 | 禁牧闭区间 | 单元测试 | JUnit5 | §2.7 | 禁牧期内/外;统计日在期内 | `inUseCount` | 仅期外+轮牧/全年计入 | | ZCZX-YZCYSJ-UT-027 | 草场 | 退化五档合计 | 单元测试 | JUnit5 | §2.8、§5.5 | G 全集 | `degradationStats` | sum(count)=`grasslandCount` | | ZCZX-YZCYSJ-UT-028 | 缓存 | 命中未过期 | 单元测试 | JUnit5 | §2.3 | 有 cache 且未过期 | `load(false)` | 不调用聚合;返回缓存 JSON | | ZCZX-YZCYSJ-UT-029 | 缓存 | forceRefresh 跳过 | 单元测试 | JUnit5 | §3.1.1 | 有缓存 | `load(true)` | 强制实时计算并 UPSERT | --- ## 二、接口测试用例 | 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | ZCZX-YZCYSJ-API-001 | 看板 | 首次加载全量结构 | 接口测试 | Postman/curl | §5.1 正常流程 | UA 登录;造数完整 | `GET /dataModel/breedingIndustry/dashboard` | `code=200`;`data` 含 `statDate`、`statYear`、`overview`、`inventoryChange`、`yakInventoryStructure`、`grassland` | | ZCZX-YZCYSJ-API-002 | 看板 | 默认当前年 | 接口测试 | Postman | §2.11 | 已登录;不传 `statYear` | `GET .../dashboard` | `statYear`=服务器当前公历年 | | ZCZX-YZCYSJ-API-003 | 产业总览 | 六项指标非负 | 接口测试 | Postman | §5.2 | 已知样本 | 读 `overview` 六字段 | 与 UT 手工值一致;`grasslandAreaMu`≥0 | | ZCZX-YZCYSJ-API-004 | 存栏变动 | 公母与未标注 | 接口测试 | Postman | §5.3.1 | HERD-L | 读 `inventoryChange` | 公/母与所选年最大月一致;`unknownGenderCount=yak−公−母` | | ZCZX-YZCYSJ-API-005 | 存栏变动 | 所选年 1~N 趋势 | 接口测试 | Postman | §5.3.2 | 最大填报月=5 | `monthlyTrend` | 长度=**5**;含 `statYear`/`month`/`bullCount`/`cowCount`;末项 month=5 | | ZCZX-YZCYSJ-API-006 | 存栏变动 | 最大月与 header | 接口测试 | Postman | §5.3.1、§2.11 | HERD-L | 比 `monthlyTrend` 最后一项与 header | 公/母分别相等 | | ZCZX-YZCYSJ-API-007 | 存栏结构 | 固定三类 | 接口测试 | Postman | §5.4 | 已登录 | `yakInventoryStructure` | 长度=**3**;`categoryCode` 为 BULL/COW/INSURED;含 details | | ZCZX-YZCYSJ-API-008 | 存栏结构 | 占比之和容忍 | 接口测试 | Postman | §5.4 | 存栏>0 | sum(大类 ratio) | 99.9~100.1(四舍五入容忍) | | ZCZX-YZCYSJ-API-009 | 草场占比 | 可用/使用中 | 接口测试 | Postman | §5.5.1 | 已登录 | `grassland.availableCount/inUseCount` | 与 UT-025~026 一致 | | ZCZX-YZCYSJ-API-010 | 草场占比 | 退化五档与合计 | 接口测试 | Postman | §5.5.2 | 已登录 | `degradationStats` | 长度=5;sum(count)=`grasslandCount` | | ZCZX-YZCYSJ-API-011 | 刷新 | forceRefresh + 指定年 | 接口测试 | Postman | §5.1 | 已登录 | `GET .../dashboard?statYear=2025&forceRefresh=true` | `code=200`;`statYear` 回显 2025 | | ZCZX-YZCYSJ-API-012 | 刷新 | 同日再次加载一致性 | 接口测试 | Postman | 技术§4 一致性 | 后台数据未变 | 连续两次 `GET`(第二次 `forceRefresh=true`) | 指标一致(除非源数据变) | | ZCZX-YZCYSJ-API-013 | 数据权限 | UA 隔离 P2 | 接口测试 | Postman | §2.9 | P2 牦牛+W2;UA 登录 | `GET /dashboard` | 不含 P2 牦牛;`warningYakCount` 不含 W2 | | ZCZX-YZCYSJ-API-014 | 数据权限 | UB 仅 P2 | 接口测试 | Postman | §2.9 | UB 登录 | `GET /dashboard` | 仅 P2 牦牛;`pastureCount` 含 P2 不含 P1 | | ZCZX-YZCYSJ-API-015 | 数据权限 | ADMIN 全量 | 接口测试 | Postman | §2.9 | ADMIN 登录 | `GET /dashboard` | P1+P2 牦牛合计 | | ZCZX-YZCYSJ-API-016 | 数据权限 | U0 牦牛为零草场仍有 | 接口测试 | Postman | §2.6、§3.1.8 | U0 登录;有 G | `GET /dashboard` | 牦牛类=0;`grasslandCount`>0 | | ZCZX-YZCYSJ-API-017 | 鉴权 | 未登录 | 接口测试 | curl | §7.2 异常 | 无 Token | `GET /dashboard` | 401 或统一未登录 | | ZCZX-YZCYSJ-API-018 | 权限 | 无 query 权限 | 接口测试 | Postman | §7.1 | 角色无 `breedingIndustry:query` | `GET /dashboard` | 403 或 `msg` 无权限 | | ZCZX-YZCYSJ-API-019 | 异常 | 聚合失败 | 接口测试 | Postman/Mock | §3.1.8 | Mock Mapper 抛错 | `GET /dashboard` | 失败;`data` 空;`msg` 含「加载失败」类文案 | | ZCZX-YZCYSJ-API-020 | 异常 | 空库零值 | 接口测试 | Postman | §5.1 空态 | 新库无业务数据 | `GET /dashboard` | `code=200`;数值 0;`yakInventoryStructure` 长 **3**、`degradationStats` 长 5 | | ZCZX-YZCYSJ-API-021 | 范围 | 无维护/同步接口 | 接口测试 | Postman | §3 本期不实现 | 已登录 | `POST/PUT/DELETE /dataModel/breedingIndustry/**` | 404/405 或无权限 | | ZCZX-YZCYSJ-API-022 | 范围 | 无筛选参数 | 接口测试 | Postman | §3、§8 | 已登录 | 传 `pastureId`/`year` 等非法 Query | 忽略或 400;口径仍按 §2 默认 | | ZCZX-YZCYSJ-API-023 | 出栏 | 无变更日出栏 | 接口测试 | Postman | §2.4 | 仅 Y-O0 | `annualOutbound` | 0 | | ZCZX-YZCYSJ-API-024 | 预警 | 年内去重口径 | 接口测试 | Postman | §2.5 | W-in 双条同 yak_no | 对比 SQL `COUNT DISTINCT` | 与 `warningYakCount` 一致 | | ZCZX-YZCYSJ-API-025 | 预警 | 周期外不计 | 接口测试 | Postman | §2.5 | 仅 W-out | `warningYakCount` | 0 | | ZCZX-YZCYSJ-API-026 | 台账 | 已删档案不计 | 接口测试 | Postman | §2.3 | 牦牛 `del_flag=2` | `GET /dashboard` | `inventoryTotal` 不含该头 | --- ## 三、界面测试用例(Playwright + Google Chrome) | 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | ZCZX-YZCYSJ-UI-001 | 正常流程 | 菜单进入自动加载 | UI | Playwright+Chrome | §4.2、§5.1 | UA 有菜单;后端正常 | 登录→点击「养殖产业数据」 | 出现四块标题;`v-loading` 结束后六项卡片有数;无报错弹窗 | | ZCZX-YZCYSJ-UI-002 | 产业总览 | 六项单位与只读 | UI | Playwright+Chrome | §5.2 | 有数据 | 检查首屏卡片 | 名称含存栏/出栏/预警/农牧户/草场/面积;单位头/户/个/亩;卡片不可点击跳转 | | ZCZX-YZCYSJ-UI-003 | 存栏变动 | 公母文案 | UI | Playwright+Chrome | §5.3.1 | 有 HERD-L | 查看存栏区文案 | 显示公牛、母牛数量;**无**「未标注性别」 | | ZCZX-YZCYSJ-UI-004 | 存栏变动 | 双折线 12 月 | UI | Playwright+Chrome | §5.3.2、前端§4 | 5 月环境 | 检查 ECharts 折线 | **12** 个刻度;横轴仅「N月」;悬停显「YYYY年N月」 | | ZCZX-YZCYSJ-UI-005 | 存栏变动 | 最近月与 header | UI | Playwright+Chrome | §5.3.1 | 有 HERD-L | 比对折线最后一点与上方公/母数 | 分别一致 | | ZCZX-YZCYSJ-UI-006 | 存栏结构 | 双层饼图 | UI | Playwright+Chrome | §5.4 | 有数据 | 查看存栏结构图例/标签 | 含公牛/母牛/保险及细分;显示 % | | ZCZX-YZCYSJ-UI-007 | 草场占比 | 可用/使用中与退化 | UI | Playwright+Chrome | §5.5 | 有 G | 查看草场区 | 展示可用、使用中个数;退化列表/图五档;列表占比与图一致 | | ZCZX-YZCYSJ-UI-009 | 刷新 | 成功更新全页 | UI | Playwright+Chrome | §5.1 | 已打开页 | 点击「刷新」 | 按钮 loading/disabled;完成后四块数据更新;可选轻提示「数据已更新」 | | ZCZX-YZCYSJ-UI-010 | 刷新 | 防重复点击 | UI | Playwright+Chrome | §5.1、前端§4 | 已打开页 | 刷新未完成时连点 2 次 | 仅 1 次有效请求或第二次按钮不可用 | | ZCZX-YZCYSJ-UI-011 | 异常 | 加载失败提示 | UI | Playwright+Chrome | §5.1、§7.2 | Mock `/dashboard` 返回 500 | 进入或点刷新 | 提示「加载失败,请稍后重试」类;页面不展示上一用户/会话缓存假数据 | | ZCZX-YZCYSJ-UI-012 | 空态 | 无牦牛有草场 | UI | Playwright+Chrome | §5.1 | U0 或仅删光牦牛 | 打开页 | 牦牛相关为 0 或「—」;草场区仍有数或 0 空态不崩溃 | | ZCZX-YZCYSJ-UI-013 | 权限 | 无菜单不可进 | UI | Playwright+Chrome | §7.1 | 无 `breedingIndustry:query` | 直接访问 `#/livestockIndustry/breedingIndustry/index` | 403/无权限页/重定向;不见四块看板 | | ZCZX-YZCYSJ-UI-014 | 范围 | 无维护按钮 | UI | Playwright+Chrome | §3、§5.1 | UA 有 query | 扫描工具栏与页面 | 无新增/编辑/删除/同步/导出;仅有刷新(及返回) | | ZCZX-YZCYSJ-UI-015 | 布局 | 纵向四块可滚动 | UI | Playwright+Chrome | §5.1 | 小屏或缩窗口 | 滚动页面 | 四块标题均可达;统计日/年可选展示 | | ZCZX-YZCYSJ-UI-016 | 权限 | UB 预警隔离 | UI | Playwright+Chrome | §2.9 | UB 登录;P1、P2 均有预警 | 打开看板记 `warningYakCount`;换 UA 对比 | UB 与 UA 预警数不同;填报类指标(存栏/出栏/农牧户)全县一致 | --- ## 四、需求追溯矩阵 | 功能需求 | 单元 | 接口 | 界面 | | --- | --- | --- | --- | | §2.1 只读看板 | — | API-021 | UI-014 | | §2.2 统计日/趋势月份 | UT-018~022 | API-002、005 | UI-004 | | §2.3 存栏认定(档案) | UT-004~006 | API-003、026 | — | | §2.11 填报存栏趋势 | UT-013、018~022 | API-004~006 | UI-003~005 | | §2.4 年出栏 | UT-007~008 | API-023 | API-003 | | §2.5 预警 | UT-009~012 | API-024~025 | API-003 | | §2.6 牧场草场总览 | UT-023~024 | API-003、010 | UI-002、008 | | §2.7 可用/使用中 | UT-025~026 | API-009 | UI-008 | | §2.8 退化占比 | UT-027 | API-010 | UI-008 | | §2.9 数据权限 | UT-001~003 | API-013~016 | UI-016 | | §2.10 月末趋势(档案) | — | — | — | | §5.1 加载/刷新/空态 | UT-028~029 | API-001、011~012、019~020 | UI-001、009~012 | | §5.2 产业总览 | UT-028 | API-003 | UI-002 | | §5.3 存栏变动 | UT-013、018~022 | API-004~006 | UI-003~005 | | §5.4 牦牛存栏结构 | UT-015~017 | API-007~008 | UI-006 | | §5.5 草场占比 | UT-025~027 | API-009~010 | UI-007 | | §7 权限提示 | — | API-017~018 | UI-013 | | §3 本期不实现 | — | API-021~022 | UI-014 | --- ## 五、Playwright 执行说明(摘要) ```javascript // playwright.config 片段 use: { channel: 'chrome', locale: 'zh-CN', baseURL: process.env.RUOYI_BASE_URL } ``` 1. `beforeEach`:UI 用例先 `page.goto('/login')` 登录 UA/UB/U0/ADMIN。 2. 菜单路径以环境为准:`page.getByText('养殖产业数据').click()` 或路由 `#/livestockIndustry/breedingIndustry/index`。 3. 接口 Mock:UI-011 可用 `page.route('**/dataModel/breedingIndustry/dashboard', route => route.fulfill({ status: 500 }))`。 4. 图表断言:对 ECharts 容器检查 DOM 或拦截 XHR 校验 `monthlyTrend` 长度 **=12**。 **用例统计**:单元 **29**、接口 **26**、界面 **15**,合计 **70** 条。