7.0 KiB
7.0 KiB
name, description, created
| name | description | created |
|---|---|---|
| 前端 API 测试基础设施 | 为 Vue3+TypeScript 前端建立 Vitest 测试框架,Mock Axios 测试 11 个 API 模块 | 2026-04-25 |
前端 API 测试基础设施设计文档
一、背景与目标
当前状态
- 前端基于 Vue 3 + TypeScript + Vite + Axios
- 11 个 API 模块 (
src/api/*.ts) 封装 HTTP 请求 - 测试完全缺失:无 vitest 配置,无 .spec/.test 文件
目标
建立前端 API 层测试基础设施,确保:
- API 请求参数/响应类型正确
- 错误处理逻辑覆盖
- 前后端契约一致性验证
- CI/CD 集成准备
二、技术选型
| 项目 | 选择 | 原因 |
|---|---|---|
| 测试框架 | Vitest | Vite 生态原生支持,配置简单,ESM 原生 |
| Mock 工具 | vi.mock (Vitest 内置) | 无额外依赖,Axios mock 简洁 |
| 断言库 | Vitest expect | 内置,支持 TypeScript 类型推断 |
| 覆盖率 | @vitest/coverage-v8 | Istanbul 覆盖率报告 |
三、架构设计
目录结构
frontend/
├── vitest.config.ts # Vitest 配置文件
├── src/api/
│ ├── __tests__/ # API 测试目录
│ │ ├── contract.spec.ts # 合同 API 测试
│ │ ├── zspContract.spec.ts # 中尚鹏合同
│ │ ├── zspFinances.spec.ts # 财务模块
│ │ ├── applyDelivery.spec.ts # 提货申请
│ │ ├── deliveryDetails.spec.ts
│ │ ├── inventory.spec.ts
│ │ ├── ownershipTransfer.spec.ts
│ │ ├── company.spec.ts
│ │ ├── user.spec.ts
│ │ ├── invoice.spec.ts
│ │ ├── settlement.spec.ts
│ │ └── reconciliation.spec.ts
│ └── test-utils.ts # Mock 工具函数
└── package.json # 新增 vitest 相关依赖
Vitest 配置
// vitest.config.ts
import { defineConfig } from 'vitest/config'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [vue()],
test: {
environment: 'jsdom',
include: ['src/api/__tests__/**/*.spec.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'html'],
include: ['src/api/**/*.ts'],
exclude: ['src/api/__tests__/**', 'src/api/test-utils.ts']
}
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
}
})
Mock 工具函数
// src/api/test-utils.ts
import { vi } from 'vitest'
import { http } from '@/utils/http'
/**
* Mock http.request 方法
* @param response 模拟响应数据
* @param status HTTP 状态码 (默认 200)
*/
export function mockHttpRequest(response: any, status = 200) {
vi.spyOn(http, 'request').mockResolvedValue({
success: true,
data: response,
status
})
}
/**
* Mock HTTP 错误响应
* @param message 错误信息
* @param status HTTP 状态码
*/
export function mockHttpError(message: string, status: number) {
vi.spyOn(http, 'request').mockRejectedValue({
success: false,
message,
status
})
}
/**
* 清除所有 mock
*/
export function clearMocks() {
vi.restoreAllMocks()
}
四、测试模式
每个 API 模块测试遵循统一模式:
4.1 请求成功测试
describe('getContractList', () => {
it('应返回合同列表', async () => {
const mockData = [{ id: 1, name: '合同1' }]
mockHttpRequest(mockData)
const result = await getContractList()
expect(result.success).toBe(true)
expect(result.data).toEqual(mockData)
})
})
4.2 参数验证测试
it('带 contractType 参数应正确传递', async () => {
mockHttpRequest([])
await getContractList({ contractType: 'business' })
expect(http.request).toHaveBeenCalledWith('get', '/api/contract', {
params: { contractType: 'business' }
})
})
4.3 错误处理测试
describe('错误处理', () => {
it('401 未授权应抛出错误', async () => {
mockHttpError('Unauthorized', 401)
await expect(getContractList()).rejects.toMatchObject({
status: 401
})
})
it('500 服务器错误应抛出错误', async () => {
mockHttpError('Internal Server Error', 500)
await expect(getContractList()).rejects.toMatchObject({
status: 500
})
})
})
4.4 类型验证
it('响应应符合 BusinessContract 类型', async () => {
const mockData: BusinessContract[] = [
{
id: 1,
name: '测试合同',
contractType: 'business',
contractCode: 'C001',
// ... 其他必填字段
}
]
mockHttpRequest(mockData)
const result = await getContractList()
// TypeScript 编译时类型检查,运行时验证结构
expect(result.data[0]).toHaveProperty('id')
expect(result.data[0]).toHaveProperty('name')
})
五、API 模块测试清单
| 模块 | 文件 | 主要 API 函数 | 预估测试数 |
|---|---|---|---|
| Contract | contract.spec.ts |
getContractList, getContract, submitContract, batchUploadContracts, updateContract, deleteContract + folders/batches | 15-20 |
| ZSP Contract | zspContract.spec.ts |
getFolders, getContracts, uploadContract, createDetail, importExcel, exportExcel | 10-15 |
| ZSP Finances | zspFinances.spec.ts |
CRUD for freight/misc/service/cost/profit | 12-15 |
| Apply Delivery | applyDelivery.spec.ts |
list, get, create, update, cancel, delete | 10 |
| Delivery Details | deliveryDetails.spec.ts |
list, get, create, update, delete | 8 |
| Inventory | inventory.spec.ts |
warehouses, inbound, summary | 8 |
| Ownership Transfer | ownershipTransfer.spec.ts |
list, get, create, createWithFiles, delete | 8 |
| Company | company.spec.ts |
folders, files CRUD | 8 |
| User | user.spec.ts |
login, register, getUser, refreshToken | 8 |
| Invoice | invoice.spec.ts |
上游/下游/货代发票 CRUD | 10 |
| Settlement | settlement.spec.ts |
CRUD | 6 |
| Reconciliation | reconciliation.spec.ts |
对账单 CRUD | 6 |
总计预估:90-110 个测试用例
六、执行命令
# 安装依赖
pnpm add -D vitest @vitest/coverage-v8 jsdom
# 运行测试
pnpm test
# 运行覆盖率
pnpm test:coverage
# 监听模式
pnpm test:watch
package.json 新增脚本
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
}
}
七、CI/CD 集成预留
后续可添加 GitHub Actions 或其他 CI 配置:
# .github/workflows/test.yml (预留)
- name: Run frontend tests
run: cd frontend && pnpm test:coverage
八、验收标准
- 所有 11 个 API 模块有对应
.spec.ts文件 - 测试覆盖率 > 80%(API 模块代码行覆盖)
- 所有测试通过,无 TypeScript 编译错误
pnpm test命令可用- 覆盖率报告生成 (
coverage/index.html)
九、后续扩展方向
- 组件测试 (
src/components/) - 页面集成测试 (
src/views/) - E2E 测试 (Playwright)
- 真实后端集成测试层