# 网上培训课程 — 测试用例

> 依据：`网上培训课程功能需求.md`、`网上培训课程技术方案.md`  
> **接口 Base Path**：`/techService/onlineTrainingCourse`；鉴权与若依一致（Cookie / Token）。

**通用前置（无特殊说明）**：具备本模块权限的账号已登录（`techService:onlineTrainingCourse:list`、`techService:onlineTrainingCourse:query`）。`biz_tech_resource` 宜预置（`del_flag=0`）：

| 样本 | `resource_type` | `resource_name` | `course_topic` | `publish_status` | 说明 |
| --- | --- | --- | --- | --- | --- |
| **KC1** | 4 | 基础养殖入门 | 基础养殖 | 1 已发布 | 本模块主样本；含 mp4、`introduction` |
| **KC2** | 4 | 牦牛疫病防治要点 | 疫病防治 | 1 已发布 | 用于主题精确筛选 |
| **KC3** | 4 | 政策解读专题课 | 政策解读 | 1 已发布 | 含封面（可选） |
| **KC-D** | 4 | 未发布草稿课 | 繁育技术 | 0 未发布 | **不应**出现在本模块列表 |
| **KC-O** | 4 | 已下架旧课 | 基础养殖 | 0 且 `offline_time` 非空 | **不应**出现 |
| **KC-X** | 4 | 已删课程 | 基础养殖 | 1 | `del_flag=2`，**不应**出现 |
| **Z2** | 1 | 李专家 | — | 1 | 非视频课程，**不应**出现 |

**源库维护（交叉验证）**：通过 `/techService/techResource` 对 KC-D 发布、对 KC1 下架、对 KC-X 逻辑删除，验证本模块纳入规则（§2.2、§7）。

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

---

## 一、单元测试用例

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| ZCZX-WSYPX-UT-001 | 工具方法 | 视频文件名解析 | 单元测试 | JUnit5 | §3.1 `videoFileName` | 无 | `path=/profile/upload/2025/a/course.mp4`；`path=null`；`path=""` | 返回 `course.mp4`；返回「已上传」或约定默认文案 |
| ZCZX-WSYPX-UT-002 | 纳入规则 | 固定查询常量 | 单元测试 | JUnit5 | §2.1、§2.3 | 无 | 断言 `OnlineTrainingCourseRules` 与 `TechResourceRules` | `type=004008`、`publish=1`、`delFlag=0` 一致 |
| ZCZX-WSYPX-UT-003 | Service | 列表 Vo 映射 | 单元测试 | JUnit5+Mockito | §3.1 | Mock 返回 KC1 实体行 | `selectList` | `courseTitle`=资源名；`courseIntro`=简介；`courseTopic` 一致；含 `videoFileName` |
| ZCZX-WSYPX-UT-004 | Service | 详情 Vo 映射 | 单元测试 | JUnit5+Mockito | §3.2 | Mock 返回含封面、视频 URL | `selectById(KC1.id)` | 含 `videoFileUrl`、`coverFileUrl`、`createTime` |
| ZCZX-WSYPX-UT-005 | Service | 详情不存在 | 单元测试 | JUnit5+Mockito | §3.2、§8 | Mapper 返回 null | `selectById(99999)` | `ServiceException`，msg 含「下线或不存在」 |
| ZCZX-WSYPX-UT-006 | Service | 详情已下架 | 单元测试 | JUnit5+Mockito | §7 | Mock 对 KC-O 条件查询无行 | `selectById(KC-O.id)` | 同上异常 |
| ZCZX-WSYPX-UT-007 | Service | 课程主题列表 | 单元测试 | JUnit5+Mockito | §3.3 | Mock 类别 rows | `selectCourseTopics` | 返回 `{code,name}` 列表 |
| ZCZX-WSYPX-UT-008 | Service | 列表不含未发布 | 单元测试 | JUnit5+Mockito | §2.2 | Mock 仅应带 published 条件 | 调用 `selectList` | Mapper 入参或 XML 固定 `publish_status=1` |
| ZCZX-WSYPX-UT-009 | Mapper | 列表 WHERE 固定条件 | 单元测试 | JUnit5 | §3.4 | 读 XML | 检查 `selectList` | `resource_type='004008'`；`publish_status=1`；`del_flag='0'` |
| ZCZX-WSYPX-UT-010 | Mapper | 标题模糊与主题精确 | 单元测试 | JUnit5 | §3.1 | 读 XML | 检查动态 SQL | `resource_name like`；`course_topic =` |
| ZCZX-WSYPX-UT-011 | Mapper | 列表排序 | 单元测试 | JUnit5 | §3.1 | 读 XML | 检查 `order by` | `create_time desc, id desc` |
| ZCZX-WSYPX-UT-012 | Mapper | 列表不含视频 URL | 单元测试 | JUnit5 | §3.1 | 读 `selectList` 列 | 对比 `selectById` | 列表 SQL 无 `video_file_url`/`cover_*`（或 Vo 不映射） |
| ZCZX-WSYPX-UT-013 | Mapper | 主题 DISTINCT | 单元测试 | JUnit5 | §3.3 | 读 XML | `selectDistinctCourseTopics` | 含 §2.1 三条件；`course_topic` 非空 |

---

## 二、接口测试用例

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| ZCZX-WSYPX-API-001 | 列表 | 默认分页排序 | 接口测试 | Postman | §5.1.2、§3.1 | 有 KC1/KC2 | `GET .../list` | `code=200`；`rows`≤20；仅 `004008` 已发布；`createTime` 新在前 |
| ZCZX-WSYPX-API-002 | 列表 | 课程标题模糊 | 接口测试 | Postman | §2.4 | 有 KC1 | `courseTitle=养殖` | 含 KC1；不含 KC2 |
| ZCZX-WSYPX-API-003 | 列表 | 课程主题精确 | 接口测试 | Postman | §2.4 | 有 KC2 | `courseTopic=005002` | 仅 KC2；`courseTopic=005` 无结果 |
| ZCZX-WSYPX-API-004 | 列表 | 标题+主题组合 | 接口测试 | Postman | §5.1.1 | 有 KC1 | `courseTitle=基础`+`courseTopic=005001` | 仅 KC1 |
| ZCZX-WSYPX-API-005 | 列表 | 筛选无结果 | 接口测试 | Postman | §8 | 已登录 | `courseTitle=不存在xyz` | `rows=[]`；`total=0` |
| ZCZX-WSYPX-API-006 | 列表 | 不含未发布 | 接口测试 | Postman | §7 | 有 KC-D | `GET list` | 无 KC-D |
| ZCZX-WSYPX-API-007 | 列表 | 不含已下架 | 接口测试 | Postman | §7 | 有 KC-O | `GET list` | 无 KC-O |
| ZCZX-WSYPX-API-008 | 列表 | 不含已删除 | 接口测试 | Postman | §7 | 有 KC-X | `GET list` | 无 KC-X |
| ZCZX-WSYPX-API-009 | 列表 | 不含非视频类型 | 接口测试 | Postman | §7 | 有 Z2 | `GET list` | 无 Z2 |
| ZCZX-WSYPX-API-010 | 列表 | 分页参数 | 接口测试 | Postman | §3.1 | ≥21 条已发布课程 | `pageSize=10&pageNum=2` | 第 2 页 10 条；`total` 正确 |
| ZCZX-WSYPX-API-011 | 列表 | 行字段结构 | 接口测试 | Postman | §3.1 | 有 KC1 | `GET list` 取 KC1 行 | 含 `id,courseTitle,courseIntro,courseTopic,videoFileName`；无 `videoFileUrl` |
| ZCZX-WSYPX-API-012 | 详情 | 有效 id | 接口测试 | Postman | §5.2.2、§3.2 | 有 KC1 | `GET /{KC1.id}` | `code=200`；含简介全文、`videoFileUrl`、`courseTopic` |
| ZCZX-WSYPX-API-013 | 详情 | 含封面样本 | 接口测试 | Postman | §5.2.2 | 有 KC3 | `GET /{KC3.id}` | 含 `coverFileUrl`（或路径） |
| ZCZX-WSYPX-API-014 | 详情 | 无封面样本 | 接口测试 | Postman | §5.2.2 | KC1 无封面 | `GET /{KC1.id}` | `coverFileUrl` 空或 null |
| ZCZX-WSYPX-API-015 | 详情 | 未发布 id | 接口测试 | Postman | §5.2.3 | 有 KC-D | `GET /{KC-D.id}` | 失败；`msg` 含「下线或不存在」 |
| ZCZX-WSYPX-API-016 | 详情 | 已下架 id | 接口测试 | Postman | §5.2.3 | 有 KC-O | `GET /{KC-O.id}` | 同上 |
| ZCZX-WSYPX-API-017 | 详情 | 已删除 id | 接口测试 | Postman | §5.2.3 | 有 KC-X | `GET /{KC-X.id}` | 同上 |
| ZCZX-WSYPX-API-018 | 详情 | 不存在 id | 接口测试 | Postman | 异常 | 已登录 | `GET /999999999` | 失败；可读 `msg` |
| ZCZX-WSYPX-API-019 | 详情 | 非视频已发布 id | 接口测试 | Postman | §7 | 有 Z2 | `GET /{Z2.id}` | 失败（无纳入行） |
| ZCZX-WSYPX-API-020 | 主题下拉 | courseTopics | 接口测试 | Postman | §3.3 | 有类别数据 | `GET .../courseTopics` | `data` 为 `{code,name}` 数组；含 `005001`/`基础养殖` 等 |
| ZCZX-WSYPX-API-021 | 交叉 | 源库发布后可见 | 接口测试 | Postman | §10 | KC-D 未发布 | `techResource` 发布 KC-D→本模块 `list` | 列表出现；`GET detail` 成功 |
| ZCZX-WSYPX-API-022 | 交叉 | 源库下架后不可见 | 接口测试 | Postman | §10 | KC1 已发布 | `techResource` 下架 KC1→本模块 `list`+`detail` | 列表无 KC1；详情失败 |
| ZCZX-WSYPX-API-023 | 写接口 | 无 POST 新增 | 接口测试 | Postman | §3、§3.2 | 已登录 | `POST .../onlineTrainingCourse` | 404 或 405；或权限拒绝 |
| ZCZX-WSYPX-API-024 | 写接口 | 无 PUT/DELETE | 接口测试 | Postman | 只读 | 已登录 | `PUT`、`DELETE /{id}` | 404/405 或权限拒绝 |
| ZCZX-WSYPX-API-025 | 鉴权 | 未登录 | 接口测试 | curl | 安全 | 无 Token | `GET list` | 401 或统一未登录 |
| ZCZX-WSYPX-API-026 | 权限 | 无 list 权限 | 接口测试 | Postman | §6 | 仅 query 权 | `GET list` | 403 或业务无权限 |
| ZCZX-WSYPX-API-027 | 权限 | 无 query 权限 | 接口测试 | Postman | §6 | 仅 list 权 | `GET /{KC1.id}` | 403 或业务无权限 |

---

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

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

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| ZCZX-WSYPX-UI-001 | 列表 | 默认展示列 | UI 测试 | Playwright+Chrome | §5.1.3 | 已登录；有 KC1/KC2 | 进入「网上培训课程」 | 列含课程标题、简介、主题、视频文件、操作；有 KC1/KC2 |
| ZCZX-WSYPX-UI-002 | 列表 | 课程主题筛选 | UI 测试 | Playwright+Chrome | §5.1.1 | 有 KC2 | 下拉选「疫病防治」(005002)→搜索 | 仅 KC2；选「繁育技术」且无 KC 时为空 |
| ZCZX-WSYPX-UI-003 | 列表 | 课程标题筛选 | UI 测试 | Playwright+Chrome | §5.1.1 | 有 KC1 | 输入「养殖」→搜索 | 含 KC1；输入「不存在xyz」无数据 |
| ZCZX-WSYPX-UI-004 | 列表 | 重置 | UI 测试 | Playwright+Chrome | §5.1.1 | 已筛选 | 搜索→点「重置」 | 条件清空；恢复默认列表 |
| ZCZX-WSYPX-UI-005 | 列表 | 无维护按钮 | UI 测试 | Playwright+Chrome | §5.1.4、§3.2 | 已登录 | 查看工具栏与行操作 | 无新增/编辑/删除/发布/下架；仅有「查看」 |
| ZCZX-WSYPX-UI-006 | 列表 | 未发布不可见 | UI 测试 | Playwright+Chrome | §7 | 仅有 KC-D 未发布、无已发布 | 打开列表 | 空状态「暂无…」或等价；无 KC-D |
| ZCZX-WSYPX-UI-007 | 列表 | 视频列不内嵌播放 | UI 测试 | Playwright+Chrome | §5.1.3 | 有数据 | 查看列表视频列 | 为文件名/文案；无 `<video>` 播放器 |
| ZCZX-WSYPX-UI-008 | 详情 | 查看只读全字段 | UI 测试 | Playwright+Chrome | §5.2.2 | 有 KC1 | 点「查看」 | 弹窗/页展示标题、简介全文、主题、视频可播、创建时间；无保存按钮 |
| ZCZX-WSYPX-UI-009 | 详情 | 封面展示 | UI 测试 | Playwright+Chrome | §5.2.2 | 有 KC3 含封面 | 查看 KC3 | 封面预览可见 |
| ZCZX-WSYPX-UI-010 | 详情 | 无封面占位 | UI 测试 | Playwright+Chrome | §5.2.2 | KC1 无封面 | 查看 KC1 | 封面区「—」或占位 |
| ZCZX-WSYPX-UI-011 | 详情 | 关闭返回列表 | UI 测试 | Playwright+Chrome | §4.1 | 已打开详情 | 关闭/返回 | 回到列表；筛选条件保持 |
| ZCZX-WSYPX-UI-012 | 详情 | 下线课程提示 | UI 测试 | Playwright+Chrome | §5.2.3 | 记下 KC1 id；源库下架 KC1 | 直接访问详情或刷新后点原「查看」 | 提示「已下线或不存在」；无有效视频 |
| ZCZX-WSYPX-UI-013 | 交叉 | 源库发布后列表出现 | UI 集成 | Playwright+Chrome | §10 | KC-D 未发布 | 视频课程库发布 KC-D→刷新本模块 | 列表出现 KC-D |
| ZCZX-WSYPX-UI-014 | 交叉 | 源库下架后列表消失 | UI 集成 | Playwright+Chrome | §10 | KC2 在列表 | 视频课程库下架 KC2→刷新 | KC2 不在列表 |
| ZCZX-WSYPX-UI-015 | 权限 | 无 list 菜单 | UI 测试 | Playwright+Chrome | §6 | 账号无 list 权 | 登录后看菜单 | 无「网上培训课程」或进页 403 |
| ZCZX-WSYPX-UI-016 | 权限 | 无 query 禁用查看 | UI 测试 | Playwright+Chrome | §6 | 仅 list 无 query | 进入列表 | 「查看」不可点或点击提示无权限 |
| ZCZX-WSYPX-UI-017 | 分页 | 翻页 | UI 测试 | Playwright+Chrome | §5.1.2 | >20 条已发布课 | 翻到第 2 页 | 数据切换；条数符合分页 |
| ZCZX-WSYPX-UI-018 | 端到端 | 查-看-筛 | UI 集成 | Playwright+Chrome | §4.1 | 有 KC1/KC2 | 主题筛选→查看 KC2→关闭→标题筛选→重置 | 全程无报错；字段与 API 一致 |

---

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

- 安装：`npm i -D @playwright/test`；`npx playwright install chrome`。  
- 配置：`use: { channel: 'chrome', locale: 'zh-CN', baseURL: 'http://localhost:80' }`；`storageState` 复用登录态。  
- 路由：`page.goto('/techService/onlineTrainingCourse')`（以菜单 `component` 为准）。  
- 筛选：`page.getByLabel('课程主题')` 或 placeholder「请选择」；`page.getByLabel('课程标题')`（若页面有标题框）。  
- 查看：`page.getByRole('button', { name: '查看' }).first().click()`；断言 `page.getByText('课程简介')`、视频区域 `video` 或播放器容器。  
- 断言无维护：`expect(page.getByRole('button', { name: '新增' })).toHaveCount(0)`。  
- 交叉用例：另开页或 API 调用 `/techService/techResource` 发布/下架后 `page.reload()`。

---

## 覆盖对照

| 类别 | 单元 UT | 接口 API | 界面 UI |
| --- | --- | --- | --- |
| 正常流程 | UT-003～004、007 | API-001～005、011～014、020 | UI-001～004、008～011、018 |
| 异常流程 | UT-005～006 | API-005、015～019、018 | UI-003、006、012 |
| 纳入约束 | UT-002、008～013 | API-006～009、019 | UI-006、013～014 |
| 只读约束 | — | API-023～024 | UI-005 |
| 源库交叉 | — | API-021～022 | UI-013～014 |
| 权限/鉴权 | — | API-025～027 | UI-015～016 |

---

## 功能需求追溯（自查）

| 需求章节 | 要点 | 主要对应用例 |
| --- | --- | --- |
| §2.2 纳入规则 | 已发布视频、未删 | UT-008～009；API-006～009、021～022；UI-006、013～014 |
| §5.1 列表 | 模糊标题、精确主题、列、分页 | API-001～005、010～011；UI-001～004、017 |
| §5.2 详情 | 全字段、视频、封面、失效 | UT-004～006；API-012～018；UI-008～012 |
| §5.1.4 / §3.2 | 无维护能力 | API-023～024；UI-005 |
| §6 权限 | list / query | API-025～027；UI-015～016 |
| §10 源库衔接 | 发布/下架联动 | API-021～022；UI-013～014 |

---

## 修订记录

| 版本 | 说明 |
| --- | --- |
| 1.0 | 初版：单元 13、接口 27、UI 18；覆盖只读 list/detail/courseTopics、纳入规则、源库交叉、权限；Playwright+Chrome；编号前缀 **ZCZX-WSYPX** |
