# 畜牧监控 — 测试用例

> 依据：`畜牧监控功能需求.md`（v1.3）、`畜牧监控技术方案.md`（v1.3）  
> **接口 Base Path**：`/videoSurveillance/livestockMonitor`；鉴权与若依一致（Cookie / Token）。

**通用前置（无特殊说明）**：具备本模块权限的账号已登录（`videoSurveillance:livestockMonitor:list|query|add|edit|remove|sync`）。主数据宜预置：

| 样本 | 类型 | 名称 | 状态 | 用途 |
| --- | --- | --- | --- | --- |
| **P1** | 养殖主体 `owner_type=1` | 巴青牧场 | `biz_pasture` 正常、`del_flag=0` | 关联监控 C1 |
| **P2** | 养殖主体 | 停业牧场 | `biz_status=2` | 不可选/保存失败 |
| **M1** | 交易市场 `owner_type=2` | 巴青县交易市场 | `operate_status=1` | 关联监控 C2 |
| **M2** | 交易市场 | 注销市场 | `operate_status=3` | 不可选/保存失败 |

`biz_livestock_monitor`（`del_flag=0`）：

| 样本 | 监控名称 | monitor_id | 所属主体 | 圈舍 | 视频来源 | 要点 |
| --- | --- | --- | --- | --- | --- | --- |
| **C1** | 圈舍监控1 | 50001 | P1 | 1号圈舍 | wvp | 列表/改删/实时预览主样本 |
| **C2** | 东门监控 | 50002 | M1 | 东门 | ys7 | 交易市场主体 |
| **C3** | 圈舍监控1 | 50003 | P1 | 2号圈舍 | wvp | 与 C1 **同名**（唯一性不校验） |

**合法新增 Body 示例**：`monitorId=50099`，`monitorName=测试监控`，`videoSource=wvp`，`ownerType=1`，`ownerId={P1.id}`，`enclosureName=1号栏`，`installLocation=1号栏`。

**第三方 stub**：`thirdparty/stub-cameras.json`（同步）；`stub-camera-play-urls.json`（`/playUrl` 实时预览）；配置 `third-party.farming.mode=stub`。

**界面（UI）测试**：**Playwright** + **Chromium**（`channel: 'chrome'` 使用本机 **Google Chrome**）。

---

## 一、单元测试用例

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| ZCZX-XMJK-UT-001 | 参数校验 | 监控名称 | 单元测试 | JUnit5 | §3.9 | 无 | 空、纯空白、11 字、10 字 trim | 空/空白/超长失败；合法通过 |
| ZCZX-XMJK-UT-002 | 参数校验 | 安装位置 | 单元测试 | JUnit5 | §3.9 | 无 | 空、11 字、10 字 | 可选；超长失败；合法通过 |
| ZCZX-XMJK-UT-003 | 参数校验 | 视频来源 | 单元测试 | JUnit5 | §3.9 | 无 | 空、非法值、wvp/ys7/url | 非法失败；合法通过 |
| ZCZX-XMJK-UT-004 | 参数校验 | 摄像头 ID | 单元测试 | JUnit5 | §3.9 | 无 | 空、33 字、合法 | 空/超长失败；通过 |
| ZCZX-XMJK-UT-005 | 参数校验 | 主体类型 | 单元测试 | JUnit5 | §2.2 | 无 | `ownerType=0/3`；`1/2` | 非法失败；1/2 进入后续校验 |
| ZCZX-XMJK-UT-006 | 主体校验 | 养殖主体正常 | 单元测试 | JUnit5+Mockito | §2.3 | Mock P1 存在且正常 | `validateOwner(1,P1.id)` | 通过；可解析 `ownerName` |
| ZCZX-XMJK-UT-007 | 主体校验 | 牧场停业 | 单元测试 | JUnit5+Mockito | 需求 §2.2 | Mock P2 | `validateOwner(1,P2.id)` | 失败；主体不存在或已停用 |
| ZCZX-XMJK-UT-008 | 主体校验 | 市场正常 | 单元测试 | JUnit5+Mockito | §2.3 | Mock M1 | `validateOwner(2,M1.id)` | 通过 |
| ZCZX-XMJK-UT-009 | 主体校验 | 市场注销 | 单元测试 | JUnit5+Mockito | §2.3 | Mock M2 | `validateOwner(2,M2.id)` | 失败 |
| ZCZX-XMJK-UT-010 | 唯一性 | 名称可重复 | 单元测试 | JUnit5+Mockito | 需求 | 库已有 C1 | 再 `validateRowForSave` 同名 | 通过 |
| ZCZX-XMJK-UT-011 | Service | 新增冗余主体名 | 单元测试 | JUnit5+Mockito | §2.3 | Mock 主数据 | `insert` 合法行 | `owner_name` 与主数据名称一致 |
| ZCZX-XMJK-UT-012 | Service | 逻辑删除 | 单元测试 | JUnit5+Mockito | §3.5 | Mock Mapper | `remove(id)` | `del_flag=2` |
| ZCZX-XMJK-UT-013 | Service | 已删不可改 | 单元测试 | JUnit5+Mockito | 需求 §5.3 | `del_flag=2` | `update` | 失败 |
| ZCZX-XMJK-UT-014 | ownerOptions | 仅正常主体 | 单元测试 | JUnit5+Mockito | §3.6 | 库含 P1/P2/M1/M2 | `listOwnerOptions(null)` | 仅含 P1、M1 |
| ZCZX-XMJK-UT-015 | ownerOptions | 关键字模糊 | 单元测试 | JUnit5+Mockito | §3.6 | 有 P1「巴青」 | `keyword=巴青` | 含 P1 |
| ZCZX-XMJK-UT-016 | Mapper | 名称模糊 SQL | 单元测试 | JUnit5 | §3.9 | 审阅 XML | `monitor_name LIKE CONCAT` |
| ZCZX-XMJK-UT-017 | Mapper | 主体精确 SQL | 单元测试 | JUnit5 | §3.9 | 审阅 XML | `owner_type` AND `owner_id` 成对 |
| ZCZX-XMJK-UT-018 | Mapper | 列表范围 | 单元测试 | JUnit5 | §3.9 | 审阅 XML | `del_flag='0'`；含 `monitor_id`；**无** `video_url` |
| ZCZX-XMJK-UT-019 | 第三方同步 | 空列表 | 单元测试 | JUnit5+Mockito | §3.7 | stub 空 | `syncFromThirdParty` | insert/update=0 |
| ZCZX-XMJK-UT-020 | 第三方同步 | 新增与更新 | 单元测试 | JUnit5+Mockito | §3.7 | 2 条摄像头 | `sync` | insert=1, update=1 |
| ZCZX-XMJK-UT-021 | 第三方同步 | 并发拒绝 | 单元测试 | JUnit5+Mockito | §3.7 | 同步进行中 | 再次 `sync` | 「正在同步，请稍候」 |
| ZCZX-XMJK-UT-022 | 第三方同步 | 单条落库失败 | 单元测试 | JUnit5+Mockito | §3.7 | persist 抛错 | `sync` | failCount+1 |
| ZCZX-XMJK-UT-023 | 播放地址 | 按 monitorId 成功 | 单元测试 | JUnit5+Mockito | §3.8 | C1 存在；Mock play-url | `getPlayUrlByMonitorId('50001')` | 返回 `videoUrl` |
| ZCZX-XMJK-UT-024 | 播放地址 | 点位不存在 | 单元测试 | JUnit5+Mockito | §3.8 | 无记录 | `getPlayUrlByMonitorId('99999')` | 失败 |
| ZCZX-XMJK-UT-025 | 播放地址 | 已删不可预览 | 单元测试 | JUnit5+Mockito | §3.8 | `del_flag=2` | `getPlayUrlByMonitorId` | 失败 |

---

## 二、接口测试用例

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| ZCZX-XMJK-API-001 | 列表 | 默认分页排序 | 接口测试 | Postman | §3.1 | 有 C1～C3 | `GET /list` | `code=200`；含 `ownerTypeName`；时间倒序 |
| ZCZX-XMJK-API-002 | 列表 | 名称模糊 | 接口测试 | Postman | §5.1 | 有 C1 | `monitorName=圈舍` | 含 C1、C3 |
| ZCZX-XMJK-API-003 | 列表 | 主体精确 | 接口测试 | Postman | §5.1 | 有 C2 | `ownerType=2&ownerId={M1.id}` | 仅含 C2 |
| ZCZX-XMJK-API-004 | 列表 | 组合筛选 | 接口测试 | Postman | §5.1 | 有 C1 | `monitorName=圈舍`+P1 主体参数 | 含 C1、C3 |
| ZCZX-XMJK-API-005 | 列表 | 不含已删除 | 接口测试 | Postman | §5.5 | 某 id 已删 | `GET /list` | 无该 id |
| ZCZX-XMJK-API-006 | 列表 | 含监控字段 | 接口测试 | Postman | §3.1 | 有 C1 | `GET /list` | 行含 `monitorId`、`videoSource`；**无** `videoUrl` |
| ZCZX-XMJK-API-007 | ownerOptions | 全量选项 | 接口测试 | Postman | §3.6 | 有 P1/M1 | `GET /ownerOptions` | `code=200`；项含 `ownerType/ownerId/ownerName` |
| ZCZX-XMJK-API-008 | ownerOptions | 关键字 | 接口测试 | Postman | §3.6 | 有 P1 | `keyword=巴青` | 含 P1 |
| ZCZX-XMJK-API-009 | 新增 | 养殖主体监控 | 接口测试 | Postman | §5.2 | 已登录 | `POST` 合法 Body 绑 P1 | `code=200`；`ownerName` 与 P1 一致 |
| ZCZX-XMJK-API-010 | 新增 | 交易市场监控 | 接口测试 | Postman | §5.2 | 已登录 | `POST` `ownerType=2`+M1 | 成功 |
| ZCZX-XMJK-API-011 | 新增 | 同名允许 | 接口测试 | Postman | 需求 | 已有 C1 | `POST` 与 C1 同名 | `code=200`（第二条） |
| ZCZX-XMJK-API-012 | 新增 | 缺监控名称 | 接口测试 | Postman | §5.2 | 已登录 | 缺 `monitorName` | 失败 |
| ZCZX-XMJK-API-013 | 新增 | 名称超长 | 接口测试 | Postman | §5.2 | 已登录 | `monitorName` 11 字 | 失败 |
| ZCZX-XMJK-API-014 | 新增 | 视频来源非法 | 接口测试 | Postman | §3.9 | 已登录 | `videoSource=invalid` | 失败 |
| ZCZX-XMJK-API-015 | 新增 | 停业牧场主体 | 接口测试 | Postman | §2.2 | 已登录 | `ownerType=1`+P2.id | 失败 |
| ZCZX-XMJK-API-016 | 新增 | 注销市场主体 | 接口测试 | Postman | §2.2 | 已登录 | `ownerType=2`+M2.id | 失败 |
| ZCZX-XMJK-API-017 | 详情 | 有效 id | 接口测试 | Postman | §3.2 | 有 C1 | `GET /{id}` | 含 `monitorId`、主体类型名称；**无** `videoUrl` |
| ZCZX-XMJK-API-018 | 详情 | 已删/不存在 | 接口测试 | Postman | §8 | 已登录 | 已删或 999999 | 失败；记录不存在或已删除 |
| ZCZX-XMJK-API-019 | 修改 | 改圈舍 | 接口测试 | Postman | §3.4 | 有 C1 | `PUT` 改 `enclosureName` | 成功 |
| ZCZX-XMJK-API-020 | 修改 | 更换主体 | 接口测试 | Postman | §5.3 | 有 C1 | `PUT` 改绑 M1（type=2） | 成功；`ownerName` 更新为市场名 |
| ZCZX-XMJK-API-021 | 修改 | 已删记录 | 接口测试 | Postman | §5.3 | C1 已删 | `PUT` | 失败 |
| ZCZX-XMJK-API-022 | 删除 | 单条逻辑删 | 接口测试 | Postman | §5.5 | 新建行无依赖 | `DELETE /{id}` | 成功；`list` 不可见 |
| ZCZX-XMJK-API-023 | 删除 | 批量删除 | 接口测试 | Postman | §3.5 | 两条新行 | `DELETE /id1,id2` | 均不可见 |
| ZCZX-XMJK-API-024 | 删除 | 重复删除 | 接口测试 | Postman | 幂等 | 已删 id | 再次 `DELETE` | 失败或 0 条 |
| ZCZX-XMJK-API-025 | 端到端 | CRUD 串联 | 接口测试 | Postman | §4 | 已登录 | `POST`→`list`→`GET`→`PUT`→`DELETE` | 关键步 `code=200` |
| ZCZX-XMJK-API-026 | 鉴权 | 未登录 | 接口测试 | curl | 安全 | 无 Token | `GET /list` | 401 或统一未登录 |
| ZCZX-XMJK-API-027 | 权限 | 无新增 | 接口测试 | Postman | §6 | 仅 list | `POST` | 无权限失败 |
| ZCZX-XMJK-API-028 | 权限 | 无删除 | 接口测试 | Postman | §6 | 无 remove | `DELETE` | 无权限失败 |
| ZCZX-XMJK-API-029 | 同步 | stub 全量同步 | 接口测试 | Postman | §3.7 | `mode=stub` | `POST /sync` | `insertCount`+`updateCount`≥0；**不**写 `video_url` |
| ZCZX-XMJK-API-030 | 同步 | 并发拒绝 | 接口测试 | Postman | §3.7 | 同步进行中 | 再次 `POST /sync` | 失败；正在同步 |
| ZCZX-XMJK-API-031 | 同步 | 无 sync 权限 | 接口测试 | Postman | §4 | 无 sync | `POST /sync` | 无权限失败 |
| ZCZX-XMJK-API-032 | playUrl | stub 成功 | 接口测试 | Postman | §3.8 | C1；`mode=stub` | `GET /playUrl?monitorId=50001` | `videoUrl` 非空 |
| ZCZX-XMJK-API-033 | playUrl | 无 monitorId | 接口测试 | Postman | §3.8 | 已登录 | 缺参数 | 失败 |
| ZCZX-XMJK-API-034 | playUrl | 未登记摄像头 | 接口测试 | Postman | §3.8 | 已登录 | `monitorId=99999` | 监控点位不存在 |
| ZCZX-XMJK-API-035 | playUrl | 无 query 权限 | 接口测试 | Postman | §4 | 无 query | `GET /playUrl` | 无权限失败 |
| ZCZX-XMJK-API-036 | 响应 | 失败可读 | 接口测试 | Postman | §8 | 已登录 | 触发缺名称、非法 videoSource | `msg` 可区分场景 |

---

## 三、界面测试用例（UI）

**测试工具**：**Playwright** + **Chromium**（`channel: 'chrome'` 使用本机 **Google Chrome**）。

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| ZCZX-XMJK-UI-001 | 列表 | 默认展示 | UI 测试 | Playwright+Chrome | §5.1、原型 | 已登录；有 C1 | 进入「畜牧监控」 | 列：监控名称、所属主体、安装位置、操作 |
| ZCZX-XMJK-UI-002 | 列表 | 名称模糊搜索 | UI 测试 | Playwright+Chrome | §5.1 | 有 C1 | 监控名称填「圈舍」→**搜索** | 含 C1、C3 |
| ZCZX-XMJK-UI-003 | 列表 | 主体筛选 | UI 测试 | Playwright+Chrome | §5.1 | 有 C2 | 所属主体选 M1→搜索 | 仅 C2 |
| ZCZX-XMJK-UI-004 | 列表 | 重置 | UI 测试 | Playwright+Chrome | §5.1 | 已筛选 | 搜索→**重置** | 条件清空；列表恢复 |
| ZCZX-XMJK-UI-005 | 列表 | 未点搜索不筛 | UI 测试 | Playwright+Chrome | 平台惯例 | 有数据 | 仅改名称不点搜索 | 列表不变 |
| ZCZX-XMJK-UI-006 | 同步 | stub 同步 | UI 测试 | Playwright+Chrome | §3.3 | 有 sync | 点击**同步** | 成功提示；列表出现 stub 数据 |
| ZCZX-XMJK-UI-007 | 新增 | 主体下拉模糊 | UI 测试 | Playwright+Chrome | §2.2 | 有 P1 | 所属主体输入「巴青」 | 可选 P1；显示类型标签 |
| ZCZX-XMJK-UI-008 | 新增 | 缺必填校验 | UI 测试 | Playwright+Chrome | §5.2 | 新增弹窗 | 空名称或未选 videoSource→确定 | 校验失败；弹窗不关闭 |
| ZCZX-XMJK-UI-009 | 新增 | 名称超 10 字 | UI 测试 | Playwright+Chrome | §5.2 | 新增 | 名称输入超 10 字 | `maxlength` 或保存失败 |
| ZCZX-XMJK-UI-010 | 新增 | 取消 | UI 测试 | Playwright+Chrome | §5.2 | 新增 | 填一半→取消 | 无新行 |
| ZCZX-XMJK-UI-011 | 查看 | 详情只读 | UI 测试 | Playwright+Chrome | §5.4 | 有 C1 | 点击**查看** | 只读；含主体类型、`monitorId` |
| ZCZX-XMJK-UI-012 | 编辑 | 修改字段 | UI 测试 | Playwright+Chrome | §5.3 | 有 C1 | 编辑→改安装位置→保存 | 列表/详情已更新 |
| ZCZX-XMJK-UI-013 | 编辑 | 更换主体 | UI 测试 | Playwright+Chrome | §5.3 | 有 C1 | 编辑→改选 M1→保存 | 所属主体显示为 M1 |
| ZCZX-XMJK-UI-014 | 删除 | 确认删除 | UI 测试 | Playwright+Chrome | §5.5 | 无依赖新行 | 删除→确认 | 行消失 |
| ZCZX-XMJK-UI-015 | 删除 | 取消删除 | UI 测试 | Playwright+Chrome | §5.5 | 任意行 | 删除→取消 | 行仍在 |
| ZCZX-XMJK-UI-016 | 实时监控 | stub 播放 | UI 测试 | Playwright+Chrome | §5.6 | 有 C1；stub | 点击**查看实时监控** | 弹窗打开；LivePlayer 有地址 |
| ZCZX-XMJK-UI-017 | 实时监控 | 无 monitorId | UI 测试 | Playwright+Chrome | §5.6 | 行缺 monitorId | 点击**查看实时监控** | 提示缺少摄像头 ID |
| ZCZX-XMJK-UI-018 | 权限 | 只读角色 | UI 测试 | Playwright+Chrome | §6 | 仅 list/query | 进入模块 | 无新增/编辑/删除/同步按钮 |
| ZCZX-XMJK-UI-019 | 端到端 | 全流程 | UI 集成 | Playwright+Chrome | §4 | 权限齐备 | 同步→搜索→实时预览→编辑→删 | 无报错 |
| ZCZX-XMJK-UI-020 | 主体 | 停业不可选 | UI 测试 | Playwright+Chrome | §2.2 | 有 P2 停业 | 新增→主体下拉搜 P2 | 无选项或不可选 |

---

## Playwright 与谷歌浏览器（实施提示）

- 安装：`npm i -D @playwright/test`；`npx playwright install chrome`。  
- 配置：`use: { channel: 'chrome', locale: 'zh-CN', baseURL: 'http://localhost:80' }`；`storageState` 复用登录态。  
- 路由：`page.goto('/videoSurveillance/livestockMonitor')`（以菜单 `component` 为准）。  
- 筛选：`page.getByPlaceholder('请输入监控名称').fill('圈舍')`；所属主体用 `el-select` + 远程搜索。  
- 同步：`page.getByRole('button', { name: '同步' }).click()`；`expect(page.getByText('同步完成')).toBeVisible()`。  
- 新增：`page.getByRole('button', { name: '新增' }).click()`；填 `monitorId`、名称、视频来源等；`确定`。  
- 实时监控：`page.getByRole('button', { name: '查看实时监控' }).first().click()`；`expect(page.locator('.live-player-wrap')).toBeVisible()`。

---

## 覆盖对照

| 类别 | 单元 UT | 接口 API | 界面 UI |
| --- | --- | --- | --- |
| 正常 CRUD | UT-011 | API-009～010、017、019～020、025 | UI-011～013、019 |
| 列表筛选 | UT-016～018 | API-001～004 | UI-002～005 |
| 主体约束 | UT-006～009、014～015 | API-007～008、015～016 | UI-007、020 |
| 字段校验 | UT-001～005 | API-012～014 | UI-008～009 |
| 唯一性不校验 | UT-010 | API-011 | — |
| 逻辑删除 | UT-012～013 | API-005、022～024 | UI-014～015 |
| 第三方同步 | UT-019～022 | API-029～031 | UI-006 |
| 实时播放 | UT-023～025 | API-032～035 | UI-016～017 |
| 鉴权权限 | — | API-026～028、031、035 | UI-018 |
| ownerOptions | UT-014～015 | API-007～008 | UI-007 |
| 监控字段 | UT-003～004 | API-006 | UI-001 |

---

## 修订记录

| 版本 | 说明 |
| --- | --- |
| 1.0 | 初稿：对齐功能需求 v1.1、技术方案 v1.0；UT/API/UI；Playwright+Chrome |
| 1.1 | 对齐 v1.2 实现：新字段、移除 IP；增加第三方同步 UT/API/UI 用例 |
| 1.2 | 对齐 v1.3：移除 `video_url` 与同步阶段二；新增 `/playUrl` UT/API/UI；实时预览 LivePlayer |
