# 海洋项目管理系统 - 测试用例文档 ## 目录 1. [单元测试用例](#1-单元测试用例) 2. [集成测试用例](#2-集成测试用例) 3. [E2E测试用例](#3-e2e测试用例) --- ## 1. 单元测试用例 ### 1.1 工具函数测试 #### TC-001: formatMoney 函数测试 | 用例ID | TC-001-01 | |--------|-----------| | 测试模块 | utils/format.js | | 测试函数 | formatMoney | | 优先级 | 高 | | 前置条件 | 无 | **测试场景** | 场景 | 输入 | 预期输出 | |------|------|---------| | 正整数 | 1234 | "1,234.00" | | 小数 | 1234.56 | "1,234.56" | | 千分位 | 10000 | "10,000.00" | | 零 | 0 | "0.00" | | 负数 | -1234.56 | "-1,234.56" | | 四舍五入 | 100.123 | "100.12" | | 大数字 | 9999999999 | "9,999,999,999.00" | --- #### TC-002: formatPercentage 函数测试 | 用例ID | TC-002-01 | |--------|-----------| | 测试模块 | utils/format.js | | 测试函数 | formatPercentage | | 优先级 | 高 | | 前置条件 | 无 | **测试场景** | 场景 | 输入 | 预期输出 | |------|------|---------| | 50% | 0.5 | "50.00%" | | 100% | 1 | "100.00%" | | 0% | 0 | "0.00%" | | 小数 | 0.6666 | "66.66%" | | 负数 | -0.5 | "-50.00%" | --- #### TC-003: formatDate 函数测试 | 用例ID | TC-003-01 | |--------|-----------| | 测试模块 | utils/format.js | | 测试函数 | formatDate | | 优先级 | 高 | | 前置条件 | 无 | **测试场景** | 场景 | 输入 | 预期输出 | |------|------|---------| | 日期字符串 | "2026-01-25" | "2026-01-25" | | Date对象 | new Date("2026-01-25") | "2026-01-25" | | 时间戳 | 1706150400000 | "2026-01-25" | --- #### TC-004: validateEmail 函数测试 | 用例ID | TC-004-01 | |--------|-----------| | 测试模块 | utils/validate.js | | 测试函数 | validateEmail | | 优先级 | 高 | | 前置条件 | 无 | **测试场景** | 场景 | 输入 | 预期输出 | |------|------|---------| | 有效邮箱 | "test@example.com" | true | | 有效邮箱(带点) | "test.name@example.com" | true | | 无效邮箱(无@) | "testexample.com" | false | | 无效邮箱(无域名) | "test@" | false | | 无效邮箱(无用户名) | "@example.com" | false | | 空字符串 | "" | false | --- #### TC-005: validatePhone 函数测试 | 用例ID | TC-005-01 | |--------|-----------| | 测试模块 | utils/validate.js | | 测试函数 | validatePhone | | 优先级 | 高 | | 前置条件 | 无 | **测试场景** | 场景 | 输入 | 预期输出 | |------|------|---------| | 有效手机号 | "13800000001" | true | | 有效手机号(其他运营商) | "15900139000" | true | | 无效手机号(太短) | "1380000" | false | | 无效手机号(太长) | "138000000001" | false | | 无效手机号(非数字) | "138a0000001" | false | | 空字符串 | "" | false | --- ### 1.2 Hooks测试 #### TC-006: useAuth Hook 测试 | 用例ID | TC-006-01 | |--------|-----------| | 测试模块 | hooks/useAuth.js | | 测试Hook | useAuth | | 优先级 | 高 | | 前置条件 | AuthProvider包裹 | **测试场景** | 场景 | 操作 | 预期结果 | |------|------|---------| | 初始状态 | 渲染组件 | isAuthenticated=false, user=null, token=null | | 登录成功 | 调用login('admin', 'password123') | isAuthenticated=true, user有值, token有值 | | 登录失败 | 调用login('admin', 'wrong') | isAuthenticated=false, 显示错误提示 | | 登出 | 调用logout() | isAuthenticated=false, user=null, token=null, localStorage清空 | | hasRole | 调用hasRole(['admin']) | 返回true或false | | canEdit | 调用canEdit(projectId) | 根据角色和创建人返回true或false | --- #### TC-007: useTable Hook 测试 | 用例ID | TC-007-01 | |--------|-----------| | 测试模块 | hooks/useTable.js | | 测试Hook | useTable | | 优先级 | 中 | | 前置条件 | 无 | **测试场景** | 场景 | 操作 | 预期结果 | |------|------|---------| | 初始状态 | 初始化Hook | pagination={current:1, pageSize:10}, filters={}, sorter={} | | 页码变化 | 调用handleTableChange({current:2}) | pagination.current=2 | | 筛选变化 | 调用handleTableChange({current:1}, {engineering_type:'基建'}) | filters.engineering_type='基建' | | 排序变化 | 调用handleTableChange({current:1}, {}, {field:'signing_date', order:'desc'}) | sorter.field='signing_date', sorter.order='desc' | | 重置 | 调用resetTable() | 恢复初始状态 | | 选择行 | 调用setSelectedRowKeys([1,2,3]) | selectedRowKeys=[1,2,3] | --- #### TC-008: useDebounce Hook 测试 | 用例ID | TC-008-01 | |--------|-----------| | 测试模块 | hooks/useDebounce.js | | 测试Hook | useDebounce | | 优先级 | 低 | | 前置条件 | 无 | **测试场景** | 场景 | 操作 | 预期结果 | |------|------|---------| | 防抖生效 | 快速改变值3次 | 只返回最后一次的值,延迟300ms | | 默认延迟 | 不传delay参数 | 使用默认延迟300ms | | 自定义延迟 | 传入delay=500 | 使用自定义延迟500ms | --- ### 1.3 组件测试 #### TC-009: Button 组件测试 | 用例ID | TC-009-01 | |--------|-----------| | 测试模块 | components/Common/Button | | 测试组件 | Button | | 优先级 | 高 | | 前置条件 | 无 | **测试场景** | 场景 | Props | 预期结果 | |------|-------|---------| | 渲染按钮 | children="点击我" | 显示"点击我"文字 | | 不同类型 | type="primary" | 蓝色按钮 | | 不同类型 | type="default" | 白色按钮 | | 不同类型 | type="danger" | 红色按钮 | | 加载状态 | loading=true | 显示加载图标,禁用按钮 | | 禁用状态 | disabled=true | 按钮不可点击 | | 点击事件 | onClick=mockFn | 点击时调用mockFn | --- #### TC-010: Tag 组件测试 | 用例ID | TC-010-01 | |--------|-----------| | 测试模块 | components/Common/Tag | | 测试组件 | Tag | | 优先级 | 中 | | 前置条件 | 无 | **测试场景** | 场景 | Props | 预期结果 | |------|-------|---------| | 渲染标签 | children="基建" | 显示"基建"文字 | | 不同类型 | type="new" | 蓝色背景和文字 | | 不同类型 | type="inProgress" | 绿色背景和文字 | | 不同类型 | type="completed" | 灰色背景和文字 | | 不同类型 | type="cancelled" | 红色背景和文字 | | 自定义颜色 | color="#ff0000" | 使用自定义颜色 | --- #### TC-011: StatCard 组件测试 | 用例ID | TC-011-01 | |--------|-----------| | 测试模块 | components/Business/StatCard | | 测试组件 | StatCard | | 优先级 | 中 | | 前置条件 | 无 | **测试场景** | 场景 | Props | 预期结果 | |------|-------|---------| | 渲染卡片 | title="项目总数", value=100 | 显示标题和数值 | | 显示图标 | icon="📊" | 显示图标 | | 前缀 | prefix="¥" | 数值前显示"¥" | | 后缀 | suffix="万元" | 数值后显示"万元" | | 金额格式化 | value=1234.56 | 显示"1,234.56万元" | --- #### TC-012: Modal 组件测试 | 用例ID | TC-012-01 | |--------|-----------| | 测试模块 | components/Common/Modal | | 测试组件 | Modal | | 优先级 | 高 | | 前置条件 | 无 | **测试场景** | 场景 | Props | 预期结果 | |------|-------|---------| | 显示模态框 | visible=true | 显示模态框 | | 隐藏模态框 | visible=false | 不显示模态框 | | 标题 | title="新建项目" | 显示标题 | | 确定按钮 | onOk=mockFn, okText="保存" | 显示"保存"按钮,点击调用mockFn | | 取消按钮 | onCancel=mockFn, cancelText="取消" | 显示"取消"按钮,点击调用mockFn | | 加载状态 | confirmLoading=true | 确定按钮显示加载状态 | | 自定义宽度 | width={800} | 宽度为800px | | 点击遮罩关闭 | 点击遮罩层 | 调用onCancel | --- ### 1.4 API服务测试 #### TC-013: projectAPI 测试 | 用例ID | TC-013-01 | |--------|-----------| | 测试模块 | services/project.js | | 测试API | projectAPI | | 优先级 | 高 | | 前置条件 | 模拟api.get/post/put/delete | **测试场景** | 场景 | 调用 | 预期结果 | |------|------|---------| | 获取列表 | getList({page:1, pageSize:10}) | api.get('/projects', {params:{page:1, pageSize:10}}) | | 获取详情 | getDetail(1) | api.get('/projects/1') | | 创建项目 | create({name:'新项目'}) | api.post('/projects', {name:'新项目'}) | | 更新项目 | update(1, {name:'更新项目'}) | api.put('/projects/1', {name:'更新项目'}) | | 删除项目 | delete(1) | api.delete('/projects/1') | | 批量删除 | batchDelete([1,2,3]) | api.post('/projects/batch-delete', {ids:[1,2,3]}) | | 获取统计 | getStatistics() | api.get('/projects/statistics') | | 获取分组统计 | getGroupStatistics({groupBy:'engineering_type'}) | api.get('/projects/statistics/group', {params:{groupBy:'engineering_type'}}) | | 获取时间统计 | getTimelineStatistics({timeField:'signing_date'}) | api.get('/projects/statistics/timeline', {params:{timeField:'signing_date'}}) | | 导出项目 | export() | api.get('/projects/export', {responseType:'blob'}) | --- #### TC-014: userAPI 测试 | 用例ID | TC-014-01 | |--------|-----------| | 测试模块 | services/user.js | | 测试API | userAPI | | 优先级 | 中 | | 前置条件 | 模拟api.get/post/put/delete | **测试场景** | 场景 | 调用 | 预期结果 | |------|------|---------| | 获取列表 | getList({page:1, pageSize:10}) | api.get('/users', {params:{page:1, pageSize:10}}) | | 获取详情 | getDetail(1) | api.get('/users/1') | | 创建用户 | create({username:'test'}) | api.post('/users', {username:'test'}) | | 更新用户 | update(1, {realName:'新姓名'}) | api.put('/users/1', {realName:'新姓名'}) | | 删除用户 | delete(1) | api.delete('/users/1') | | 重置密码 | resetPassword(1, 'newPassword') | api.post('/users/1/reset-password', {new_password:'newPassword'}) | --- ## 2. 集成测试用例 ### 2.1 页面组件测试 #### TC-015: Login 页面测试 | 用例ID | TC-015-01 | |--------|-----------| | 测试模块 | pages/Login | | 测试页面 | Login | | 优先级 | 高 | | 前置条件 | 无 | **测试场景** | 场景 | 操作 | 预期结果 | |------|------|---------| | 渲染登录页 | 访问/login | 显示登录表单、Logo、用户名输入框、密码输入框、登录按钮 | | 必填字段验证 | 不输入直接点击登录 | 显示"请输入用户名"和"请输入密码"错误 | | 用户名太短 | 输入2个字符 | 显示"用户名至少3个字符"错误 | | 密码太短 | 输入5个字符 | 显示"密码至少6个字符"错误 | | 登录成功 | 输入正确用户名和密码,点击登录 | 调用login API,保存Token到localStorage,跳转到/dashboard | | 登录失败 | 输入错误密码,点击登录 | 显示"用户名或密码错误"提示 | | 记住密码 | 勾选"记住密码",点击登录 | localStorage保存用户名和密码(加密) | | 加载状态 | 点击登录按钮 | 按钮显示加载图标,禁用状态 | | Enter键提交 | 输入后按Enter键 | 触发登录 | --- #### TC-016: Dashboard 页面测试 | 用例ID | TC-016-01 | |--------|-----------| | 测试模块 | pages/Dashboard | | 测试页面 | Dashboard | | 优先级 | 高 | | 前置条件 | 已登录 | **测试场景** | 场景 | 操作 | 预期结果 | |------|------|---------| | 渲染仪表盘 | 访问/dashboard | 显示统计卡片、图表、最近项目列表 | | 加载统计卡片 | 页面加载 | 调用getBasicStatistics API,显示4个统计卡片 | | 加载图表 | 页面加载 | 调用getTimelineStatistics API,显示项目趋势图 | | 加载最近项目 | 页面加载 | 调用getProjects API,显示最近5个项目 | | 点击项目卡片 | 点击统计卡片 | 跳转到对应功能页面 | | 点击最近项目 | 点击项目项 | 跳转到项目详情页 | | 刷新数据 | 点击刷新按钮 | 重新获取所有数据 | | 自动刷新 | 等待5分钟 | 自动刷新统计数据 | --- #### TC-017: ProjectList 页面测试 | 用例ID | TC-017-01 | |--------|-----------| | 测试模块 | pages/ProjectList | | 测试页面 | ProjectList | | 优先级 | 高 | | 前置条件 | 已登录 | **测试场景** | 场景 | 操作 | 预期结果 | |------|------|---------| | 渲染列表页 | 访问/projects | 显示工具栏、项目表格、分页控件 | | 加载项目列表 | 页面加载 | 调用getList API,默认参数page=1, pageSize=10 | | 搜索项目 | 输入关键词,按Enter | 调用getList API,参数包含keyword | | 按工程类别筛选 | 选择"基建" | 调用getList API,参数engineering_type='基建' | | 按日期筛选 | 选择日期范围 | 调用getList API,参数包含signing_date_start和signing_date_end | | 按金额筛选 | 输入金额范围 | 调用getList API,参数包含contract_amount_min和contract_amount_max | | 组合筛选 | 同时设置多个条件 | 调用getList API,所有条件AND关系 | | 清除筛选 | 点击"清除"按钮 | 重置所有筛选条件,刷新列表 | | 排序 | 点击表头"签订日期" | 切换升序/降序,调用getList API,参数sort_by和sort_order | | 分页 | 点击页码 | 调用getList API,参数page更新 | | 查看项目 | 点击"查看"按钮 | 跳转到/projects/:id | | 新建项目 | 点击"新建项目"按钮 | 打开新建项目模态框 | | 编辑项目 | 点击"编辑"按钮 | 调用getDetail API,填充表单,打开编辑模态框 | | 删除项目 | 点击"删除"按钮 | 显示确认对话框,确认后调用delete API | | 权限控制 | 市场部用户查看其他部门项目 | "编辑"和"删除"按钮不显示 | | 表格行点击 | 点击表格行 | 跳转到项目详情页 | --- #### TC-018: ProjectDetail 页面测试 | 用例ID | TC-018-01 | |--------|-----------| | 测试模块 | pages/ProjectDetail | | 测试页面 | ProjectDetail | | 优先级 | 高 | | 前置条件 | 已登录 | **测试场景** | 场景 | 操作 | 预期结果 | |------|------|---------| | 渲染详情页 | 访问/projects/1 | 调用getDetail API,显示项目信息卡片 | | 信息分组显示 | 页面加载 | 显示多个信息分组(基本信息、项目时间、成本管理等) | | 格式化金额 | 显示金额字段 | 千分位分隔,保留两位小数,单位"万元" | | 格式化日期 | 显示日期字段 | 格式为YYYY-MM-DD | | 编辑项目 | 点击"编辑"按钮 | 打开编辑模态框,填充当前数据 | | 删除项目 | 点击"删除"按钮 | 显示确认对话框,确认后调用delete API,跳转到列表页 | | 返回列表 | 点击面包屑"项目管理" | 跳转到/projects | | 字段级权限 | 其他部门用户编辑 | 基础信息字段只读,其他字段可编辑 | | 金额计算 | 修改成本字段 | 自动计算总成本控制金额 | | 进度计算 | 修改进度字段 | 自动更新进度百分比 | --- #### TC-019: UserList 页面测试 | 用例ID | TC-019-01 | |--------|-----------| | 测试模块 | pages/UserList | | 测试页面 | UserList | | 优先级 | 高 | | 前置条件 | 已登录,管理员角色 | **测试场景** | 场景 | 操作 | 预期结果 | |------|------|---------| | 渲染用户列表 | 访问/users | 显示工具栏、用户表格、分页控件 | | 加载用户列表 | 页面加载 | 调用getUsers API | | 搜索用户 | 输入关键词,按Enter | 调用getUsers API,参数包含keyword | | 按部门筛选 | 选择"市场部" | 调用getUsers API,参数department='市场部' | | 按角色筛选 | 选择"admin" | 调用getUsers API,参数role='admin' | | 新建用户 | 点击"新建用户"按钮 | 打开新建用户模态框 | | 编辑用户 | 点击"编辑"按钮 | 调用getUserDetail API,填充表单,打开编辑模态框 | | 用户名只读 | 编辑模式 | 用户名字段禁用,不可修改 | | 删除用户 | 点击"删除"按钮 | 显示确认对话框,确认后调用delete API | | 重置密码 | 点击"重置密码"按钮 | 显示重置密码对话框,输入新密码后调用resetPassword API | | 权限控制 | 非管理员用户访问 | 重定向到403页或显示权限错误 | --- ### 2.2 交互流程测试 #### TC-020: 完整的项目创建流程测试 | 用例ID | TC-020-01 | |--------|-----------| | 测试模块 | 交互流程 | | 测试场景 | 项目创建流程 | | 优先级 | 高 | | 前置条件 | 已登录,有创建项目权限 | **测试步骤** | 步骤 | 操作 | 预期结果 | |------|------|---------| | 1 | 访问/projects | 显示项目列表页 | | 2 | 点击"新建项目"按钮 | 打开新建项目模态框 | | 3 | 输入合同编号"PRJ001" | 输入框显示"PRJ001" | | 4 | 输入项目名称"测试项目" | 输入框显示"测试项目" | | 5 | 选择工程类别"基建" | 下拉框显示"基建" | | 6 | 输入合同金额"100" | 输入框显示"100" | | 7 | 选择签订日期"2026-01-25" | 日期选择器显示"2026-01-25" | | 8 | 不输入必填字段,点击保存 | 显示必填字段验证错误 | | 9 | 填写所有必填字段,点击保存 | 调用create API,loading=true | | 10 | API返回成功 | 模态框关闭,列表刷新,显示成功提示"项目创建成功" | | 11 | API返回失败(合同编号重复) | 显示错误提示"合同编号已存在" | | 12 | 新项目出现在列表中 | 列表第一行显示新项目 | --- #### TC-021: 完整的项目编辑流程测试 | 用例ID | TC-021-01 | |--------|-----------| | 测试模块 | 交互流程 | | 测试场景 | 项目编辑流程 | | 优先级 | 高 | | 前置条件 | 已登录,有编辑权限 | **测试步骤** | 步骤 | 操作 | 预期结果 | |------|------|---------| | 1 | 访问/projects | 显示项目列表页 | | 2 | 找到项目PRJ001 | 列表显示该项目 | | 3 | 点击"编辑"按钮 | 调用getDetail API,打开编辑模态框 | | 4 | 表单填充当前数据 | 输入框显示项目当前值 | | 5 | 修改项目名称为"更新项目" | 输入框显示"更新项目" | | 6 | 修改合同金额为"200" | 输入框显示"200" | | 7 | 点击保存 | 调用update API,loading=true | | 8 | API返回成功 | 模态框关闭,列表刷新,显示成功提示"项目更新成功" | | 9 | API返回失败 | 显示错误提示 | | 10 | 列表显示更新后的数据 | 项目名称和金额更新 | --- #### TC-022: 完整的项目删除流程测试 | 用例ID | TC-022-01 | |--------|-----------| | 测试模块 | 交互流程 | | 测试场景 | 项目删除流程 | | 优先级 | 中 | | 前置条件 | 已登录,有删除权限 | **测试步骤** | 步骤 | 操作 | 预期结果 | |------|------|---------| | 1 | 访问/projects | 显示项目列表页 | | 2 | 找到项目PRJ001 | 列表显示该项目 | | 3 | 点击"删除"按钮 | 显示确认对话框,内容"确定要删除该项目吗?" | | 4 | 点击"取消"按钮 | 对话框关闭,项目不被删除 | | 5 | 再次点击"删除"按钮 | 显示确认对话框 | | 6 | 点击"确定"按钮 | 调用delete API | | 7 | API返回成功 | 列表刷新,显示成功提示"项目删除成功",项目从列表消失 | | 8 | API返回失败 | 显示错误提示 | | 9 | 项目不存在 | 显示404错误提示 | --- ## 3. E2E测试用例 ### 3.1 认证流程E2E测试 #### TC-E2E-001: 登录流程E2E测试 | 用例ID | TC-E2E-001 | |--------|-----------| | 测试模块 | 登录流程 | | 测试类型 | E2E | | 优先级 | 高 | | 前置条件 | 后端服务运行,测试账号存在 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 正常登录 | 1. 访问http://localhost:3000
2. 输入用户名"admin"
3. 输入密码"password123"
4. 点击登录按钮 | 1. 显示登录页
2. 自动跳转到/dashboard
3. 顶部导航显示用户信息"系统管理员(管理部)" | | 登录失败 | 1. 访问登录页
2. 输入正确用户名
3. 输入错误密码
4. 点击登录按钮 | 1. 显示错误提示"用户名或密码错误"
2. 停留在登录页
3. 输入框保留输入值 | | 字段验证 | 1. 访问登录页
2. 不输入任何内容
3. 点击登录按钮 | 1. 用户名和密码输入框显示红色边框
2. 显示"请输入用户名"和"请输入密码"提示
3. 登录按钮无法提交 | | 记住密码 | 1. 勾选"记住密码"
2. 输入用户名和密码
3. 点击登录
4. 刷新页面 | 1. 用户名和密码自动填充
2. 复选框保持选中 | --- #### TC-E2E-002: 登出流程E2E测试 | 用例ID | TC-E2E-002 | |--------|-----------| | 测试模块 | 登出流程 | | 测试类型 | E2E | | 优先级 | 高 | | 前置条件 | 已登录 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 登出 | 1. 点击顶部导航"登出"按钮
2. 点击确认对话框"确定"按钮 | 1. 显示确认对话框"确定要退出登录吗?"
2. 跳转到/login
3. localStorage清空 | | 取消登出 | 1. 点击"登出"按钮
2. 点击"取消"按钮 | 1. 对话框关闭
2. 保持在当前页面,保持登录状态 | --- ### 3.2 项目管理E2E测试 #### TC-E2E-003: 项目列表E2E测试 | 用例ID | TC-E2E-003 | |--------|-----------| | 测试模块 | 项目列表 | | 测试类型 | E2E | | 优先级 | 高 | | 前置条件 | 已登录 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 浏览列表 | 1. 点击侧边栏"项目管理"
2. 等待页面加载
3. 查看项目表格 | 1. 跳转到/projects
2. 显示项目表格
3. 表格显示项目数据,每页10条 | | 分页浏览 | 1. 点击"下一页"按钮
2. 点击第3页
3. 点击"上一页" | 1. 显示第2页数据
2. 显示第3页数据
3. 显示第2页数据 | | 搜索项目 | 1. 在搜索框输入"基建"
2. 按Enter键 | 1. 表格只显示包含"基建"的项目
2. 显示搜索结果数量 | | 筛选项目 | 1. 点击"工程类别"下拉框
2. 选择"基建"
3. 点击"签订日期"日期选择器
4. 选择日期范围
5. 点击"确定" | 1. 表格只显示基建项目
2. 签订日期在范围内的项目 | | 清除筛选 | 1. 设置多个筛选条件
2. 点击"清除"按钮 | 1. 所有筛选条件清空
2. 列表显示所有数据 | --- #### TC-E2E-004: 项目创建E2E测试 | 用例ID | TC-E2E-004 | |--------|-----------| | 测试模块 | 项目创建 | | 测试类型 | E2E | | 优先级 | 高 | | 前置条件 | 已登录,有创建项目权限 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 创建项目 | 1. 访问/projects
2. 点击"新建项目"按钮
3. 输入合同编号"PRJ999"
4. 输入项目名称"E2E测试项目"
5. 选择工程类别"基建"
6. 输入合同金额"100"
7. 选择签订日期"2026-01-25"
8. 点击"保存"按钮
9. 等待API响应 | 1. 打开新建项目模态框
2. 模态框标题"新建项目"
3-7. 所有输入框显示输入值
8. 按钮显示loading状态
9. 模态框关闭
10. 显示成功提示"项目创建成功"
11. 列表第一行显示新项目 | | 验证失败创建 | 1. 点击"新建项目"
2. 不输入必填字段
3. 点击"保存" | 1. 必填字段显示红色边框
2. 显示错误提示
3. 模态框不关闭 | --- #### TC-E2E-005: 项目编辑E2E测试 | 用例ID | TC-E2E-005 | |--------|-----------| | 测试模块 | 项目编辑 | | 测试类型 | E2E | | 优先级 | 高 | | 前置条件 | 已登录,有编辑权限 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 编辑项目 | 1. 访问/projects
2. 找到项目PRJ001
3. 点击"编辑"按钮
4. 修改项目名称为"E2E更新项目"
5. 修改合同金额为"200"
6. 点击"保存"按钮
7. 等待API响应 | 1. 打开编辑项目模态框
2. 模态框标题"编辑项目"
3. 表单填充当前数据
4-5. 输入框显示新值
6. 按钮显示loading状态
7. 模态框关闭
8. 显示成功提示"项目更新成功"
9. 列表显示更新后的数据 | | 权限限制编辑 | 1. 其他部门用户登录
2. 编辑项目PRJ001
3. 查看表单字段 | 1. 基础信息字段(合同编号、项目名称等)只读
2. 成本、财务等字段可编辑 | --- #### TC-E2E-006: 项目删除E2E测试 | 用例ID | TC-E2E-006 | |--------|-----------| | 测试模块 | 项目删除 | | 测试类型 | E2E | | 优先级 | 中 | | 前置条件 | 已登录,有删除权限 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 删除项目 | 1. 访问/projects
2. 找到项目PRJ999
3. 点击"删除"按钮
4. 查看确认对话框内容
5. 点击"确定"按钮
6. 等待API响应 | 1. 显示确认对话框
2. 对话框内容"确定要删除该项目吗?"
3. 显示项目名称和合同编号
4. 点击"确定"后
5. 显示成功提示"项目删除成功"
6. 列表刷新,项目消失 | | 取消删除 | 1. 点击"删除"按钮
2. 点击"取消"按钮 | 1. 对话框关闭
2. 项目不被删除,仍在列表中 | --- ### 3.3 用户管理E2E测试 #### TC-E2E-007: 用户列表E2E测试 | 用例ID | TC-E2E-007 | |--------|-----------| | 测试模块 | 用户列表 | | 测试类型 | E2E | | 优先级 | 高 | | 前置条件 | 已登录,管理员角色 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 浏览用户列表 | 1. 点击侧边栏"用户管理"
2. 等待页面加载 | 1. 跳转到/users
2. 显示用户表格
3. 表格显示所有用户 | | 搜索用户 | 1. 在搜索框输入"admin"
2. 按Enter键 | 1. 表格只显示匹配的用户 | | 按部门筛选 | 1. 点击"部门"下拉框
2. 选择"市场部" | 1. 表格只显示市场部用户 | | 按角色筛选 | 1. 点击"角色"下拉框
2. 选择"admin" | 1. 表格只显示管理员用户 | --- #### TC-E2E-008: 用户创建E2E测试 | 用例ID | TC-E2E-008 | |--------|-----------| | 测试模块 | 用户创建 | | 测试类型 | E2E | | 优先级 | 高 | | 前置条件 | 已登录,管理员角色 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 创建用户 | 1. 访问/users
2. 点击"新建用户"按钮
3. 输入用户名"testuser"
4. 输入密码"password123"
5. 输入真实姓名"测试用户"
6. 选择部门"管理部"
7. 选择角色"admin"
8. 点击"保存"按钮
9. 等待API响应 | 1. 打开新建用户模态框
2. 模态框标题"新建用户"
3-7. 所有输入框显示输入值
8. 按钮显示loading状态
9. 模态框关闭
10. 显示成功提示"用户创建成功"
11. 列表显示新用户 | | 用户名重复 | 1. 创建用户,用户名"admin"
2. 点击"保存" | 1. 显示错误提示"用户名已存在"
2. 模态框不关闭 | --- #### TC-E2E-009: 用户编辑E2E测试 | 用例ID | TC-E2E-009 | |--------|-----------| | 测试模块 | 用户编辑 | | 测试类型 | E2E | | 优先级 | 中 | | 前置条件 | 已登录,管理员角色 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 编辑用户 | 1. 访问/users
2. 找到用户testuser
3. 点击"编辑"按钮
4. 修改真实姓名为"测试用户更新"
5. 修改邮箱为新邮箱
6. 点击"保存"按钮
7. 等待API响应 | 1. 打开编辑用户模态框
2. 用户名字段只读
3. 其他字段可编辑
4-5. 输入框显示新值
6. 按钮显示loading状态
7. 模态框关闭
8. 显示成功提示
9. 列表显示更新后的数据 | --- #### TC-E2E-010: 用户删除E2E测试 | 用例ID | TC-E2E-010 | |--------|-----------| | 测试模块 | 用户删除 | | 测试类型 | E2E | | 优先级 | 中 | | 前置条件 | 已登录,管理员角色 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 删除用户 | 1. 访问/users
2. 找到用户testuser
3. 点击"删除"按钮
4. 点击"确定"按钮
5. 等待API响应 | 1. 显示确认对话框
2. 点击"确定"后
3. 显示成功提示"用户删除成功"
4. 列表刷新,用户消失 | --- #### TC-E2E-011: 重置密码E2E测试 | 用例ID | TC-E2E-011 | |--------|-----------| | 测试模块 | 重置密码 | | 测试类型 | E2E | | 优先级 | 中 | | 前置条件 | 已登录,管理员角色 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 重置密码 | 1. 访问/users
2. 找到用户testuser
3. 点击"重置密码"按钮
4. 输入新密码"newpassword123"
5. 点击"确定"按钮
6. 等待API响应 | 1. 显示重置密码对话框
2. 输入框显示新密码
3. 点击"确定"后
4. 显示成功提示"密码重置成功" | --- ### 3.4 统计分析E2E测试 #### TC-E2E-012: 仪表盘E2E测试 | 用例ID | TC-E2E-012 | |--------|-----------| | 测试模块 | 仪表盘 | | 测试类型 | E2E | | 优先级 | 高 | | 前置条件 | 已登录 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 查看仪表盘 | 1. 访问/dashboard
2. 等待页面加载 | 1. 显示4个统计卡片
2. 显示项目趋势图
3. 显示最近项目列表 | | 查看统计卡片 | 1. 查看统计卡片数据 | 1. 项目总数、进行中、已完成、总合同金额
2. 数值格式化(千分位、保留两位小数) | | 查看图表 | 1. 鼠标悬停在图表上 | 1. 显示Tooltip,显示详细数据 | | 点击最近项目 | 1. 点击最近项目列表项 | 1. 跳转到项目详情页 | | 刷新数据 | 1. 点击刷新按钮 | 1. 重新获取所有数据 | --- #### TC-E2E-013: 项目统计E2E测试 | 用例ID | TC-E2E-013 | |--------|-----------| | 测试模块 | 项目统计 | | 测试类型 | E2E | | 优先级 | 高 | | 前置条件 | 已登录 | **测试场景** | 场景 | 步骤 | 预期结果 | |------|------|---------| | 查看统计页 | 1. 点击侧边栏"项目统计"
2. 等待页面加载 | 1. 显示筛选工具栏
2. 显示统计图表
3. 显示分组统计表格 | | 基础统计 | 1. 查看基础统计卡片 | 1. 显示8个统计卡片
2. 数值格式化 | | 分组统计 | 1. 查看按工程类别分组 | 1. 显示饼图和柱状图
2. 显示分组统计表格 | | 时间维度统计 | 1. 选择时间维度"按月"
2. 查看折线图 | 1. 显示每月项目数量和金额趋势 | | 筛选统计 | 1. 选择工程类别"基建"
2. 选择日期范围 | 1. 所有统计只显示符合条件的数据 | | 导出报表 | 1. 点击"导出报表"按钮
2. 等待下载完成 | 1. 下载Excel文件
2. 文件名"项目统计_YYYY-MM-DD.xlsx" | --- ## 4. 测试数据准备 ### 4.1 测试用户数据 ```javascript const testUsers = [ { id: 1, username: 'admin', password: 'password123', real_name: '系统管理员', department: '管理部', role: 'admin', email: 'admin@example.com', is_active: true, }, { id: 2, username: 'market', password: 'password123', real_name: '市场部用户', department: '市场部', role: 'market', email: 'market@example.com', is_active: true, }, { id: 3, username: 'other', password: 'password123', real_name: '其他部门用户', department: '技术部', role: 'other', email: 'other@example.com', is_active: true, }, ]; ``` ### 4.2 测试项目数据 ```javascript const testProjects = [ { id: 1, project_no: 'PRJ001', name: '某电力基建工程项目', engineering_type: '基建', contract_amount: 950.00, signing_date: '2026-01-01', start_date: '2026-01-15', planned_end_date: '2026-12-31', project_department: '项目部一', project_leader: '李四', created_by: 2, }, { id: 2, project_no: 'PRJ002', name: '业扩工程项目', engineering_type: '业扩', contract_amount: 500.00, signing_date: '2026-01-10', start_date: '2026-01-20', planned_end_date: '2026-06-30', project_department: '项目部二', project_leader: '王五', created_by: 2, }, ]; ``` --- ## 5. 测试覆盖率目标 | 类型 | 目标覆盖率 | |------|----------| | 语句覆盖率 | 80% | | 分支覆盖率 | 75% | | 函数覆盖率 | 80% | | 行覆盖率 | 80% | --- **文档维护**: 前端程序员 **文档类型**: 测试用例文档 **最后更新**: 2026-01-25