Mock数据使用指南
本项目Mock数据管理的完整规范,涵盖前端开发、单元测试和集成测试中的Mock策略
📋 指南使用说明
核心目的:本指南为前端开发提供Mock数据使用的统一标准,确保在开发和测试阶段的数据一致性和可维护性。
适用范围:
- 后端API尚未就绪时的前端开发
- 单元测试中的API调用模拟
- 集成测试中的数据模拟
- Storybook组件展示数据
Mock策略分类:
- 开发Mock:通过
useMockData()composable提供数据 - 测试Mock:使用MSW或直接mock API调用
- Mock API服务器:通过
apiMock/目录提供静态JSON响应
🏗️ Mock数据架构概览
环境控制
通过环境变量 NUXT_MOCK_API_PROXY 控制Mock模式:
NUXT_MOCK_API_PROXY=1 # 使用Mock API服务器(./apiMock目录)
NUXT_MOCK_API_PROXY=0 # 连接真实后端API
nuxt.config.ts配置:
export default defineNuxtConfig({
runtimeConfig: {
public: {
mockApiProxy: process.env.NUXT_MOCK_API_PROXY,
},
},
})
Mock数据源层级
frontend/
├── src/
│ ├── composables/
│ │ └── useMockData.ts # 主要Mock数据composable
├── apiMock/ # Mock API服务器目录
│ └── api/
│ ├── auth/
│ │ └── login.json # 登录接口Mock数据
│ └── users/
│ └── index.json # 用户列表Mock数据
└── tests/
└── setup/
└── msw.ts # MSW处理器配置
🛠️ 开发阶段Mock数据
1. useMockData() Composable
文件位置:frontend/src/composables/useMockData.ts
核心功能:
// 获取用户列表(模拟)
fetchUsers(): Promise<User[]>
// 获取单个用户
fetchUser(id: number): Promise<User>
// 模拟保存操作
saveData<T>(data: T): Promise<T>
// 模拟删除操作
deleteData(id: number): Promise<boolean>
// 模拟搜索
searchData<T>(keyword: string): Promise<T[]>
// 模拟分页数据
fetchPaginatedData<T>(page: number, pageSize: number): Promise<PaginatedResponse<T>>
设计原则:
- 模拟网络延迟(默认500ms)
- 返回类型与真实API保持一致
- 支持错误场景模拟
- 便于后期平滑替换为真实API
2. 页面/组件中使用示例
<script setup lang="ts">
import { useMockData } from '~/composables/useMockData'
const { fetchUsers, saveData } = useMockData()
const users = ref<User[]>([])
const loading = ref(false)
onMounted(async () => {
loading.value = true
users.value = await fetchUsers() // 使用Mock数据
loading.value = false
})
const handleSave = async (data: UserForm) => {
const result = await saveData(data) // 模拟保存
console.log('Mock save result:', result)
}
</script>
3. Mock API服务器
工作原理:
- 开发模式下,Nuxt扫描
apiMock目录 - 将
.json文件作为API端点响应 - 支持RESTful路由模式
目录结构示例:
apiMock/
├── api/
│ ├── auth/
│ │ └── login.json # POST /api/auth/login
│ ├── users/
│ │ ├── index.json # GET /api/users
│ │ └── [id].json # GET /api/users/:id
│ └── agency-groups/
│ └── index.json # GET /api/agency-groups
JSON文件格式:
{
"messageId": "mock-001",
"data": {
"agencyGroups": [
{
"agencyGroupId": 1,
"agencyGroupName": "テストグループA",
"groupDescription": "説明文"
}
]
},
"error": null
}
🧪 测试阶段Mock数据
1. 前端单元测试(Vitest)
方案A:使用MSW(推荐用于集成测试)
// tests/setup/msw.ts
import { setupServer } from 'msw/node'
import { http, HttpResponse } from 'msw'
export const handlers = [
http.get('/api/users/:id', ({ params }) => {
const { id } = params
return HttpResponse.json({
messageId: 'test-001',
data: {
id,
name: 'Mock User',
email: 'mock@example.com'
},
error: null
})
}),
]
export const server = setupServer(...handlers)
方案B:直接mock ofetch(用于单元测试)
// userApi.spec.ts
import { describe, test, expect, vi, beforeEach } from 'vitest'
import { fetchUser } from './userApi'
vi.mock('ofetch', () => ({
default: vi.fn(),
}))
describe('userApi', () => {
test('should fetch user data successfully', async () => {
// Arrange
const mockUser = {
messageId: 'test-001',
data: { id: 1, name: 'Alice', email: 'alice@example.com' },
error: null
}
const { default: ofetch } = await import('ofetch')
;(ofetch as any).mockResolvedValue(mockUser)
// Act & Assert
const result = await fetchUser(1)
expect(result).toEqual(mockUser)
})
})
2. 后端单元测试(Java + Spring Boot)
Controller测试(@WebMvcTest)
@WebMvcTest(UserController.class)
class UserControllerTest {
@MockBean
private UserService userService;
@Autowired
private MockMvc mockMvc;
@Test
void shouldReturnUserWhenUserExists() throws Exception {
// Arrange
Long userId = 1L;
UserResponse mockUser = new UserResponse(userId, "Alice", "alice@example.com");
when(userService.getUserById(userId)).thenReturn(mockUser);
// Act & Assert
mockMvc.perform(get("/api/users/{id}", userId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.id").value(1));
}
}
Service测试(Mockito)
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void shouldGetUserById() {
// Arrange
Long userId = 1L;
User mockUser = new User(userId, "Alice", "alice@example.com");
when(userRepository.findById(userId)).thenReturn(Optional.of(mockUser));
// Act & Assert
UserResponse result = userService.getUserById(userId);
assertThat(result).isNotNull();
}
}
📋 Mock数据规范
1. 数据格式规范
标准消息结构(与真实API保持一致):
interface ApiResponse<T> {
messageId: string // 消息ID(用于追踪)
data: T | null // 响应数据
error: {
code: string // 错误代码
message: string // 错误消息
details?: any // 错误详情
} | null
}
2. Mock数据文件命名
| 场景 | 命名规则 | 示例 |
|---|---|---|
| API响应数据 | api/资源名/操作.json | api/users/index.json |
| 列表数据 | 资源名-list.json | users-list.json |
| 单条数据 | 资源名-detail.json | user-detail.json |
| 错误响应 | 资源名-error.json | login-error.json |
3. Mock函数命名
| 操作类型 | 命名前缀 | 示例 |
|---|---|---|
| 获取列表 | fetchXxx | fetchUsers() |
| 获取单个 | fetchXxxById | fetchUserById(1) |
| 保存数据 | saveXxx | saveUser(data) |
| 删除数据 | deleteXxx | deleteUser(1) |
| 搜索数据 | searchXxx | searchUsers(keyword) |
| 分页数据 | fetchXxxPaginated | fetchUsersPaginated(1, 10) |
✅ Mock数据最佳实践
推荐做法
- 统一入口:通过
useMockData()统一管理Mock函数 - 延迟模拟:使用
delay()模拟网络延迟(默认500ms) - 数据真实:Mock数据应贴近真实业务场景
- 类型安全:Mock函数返回类型与真实API一致
- 环境分离:使用环境变量控制Mock开关
- 错误场景:模拟网络错误、业务错误等异常情况
禁止事项
- ❌ 生产环境使用Mock数据
- ❌ 在组件中硬编码Mock数据逻辑
- ❌ 测试中发起真实API调用
- ❌ Mock函数包含复杂业务逻辑
- ❌ 使用
any类型,保持类型安全
🔄 Mock到真实API的迁移
迁移策略
阶段一:所有调用通过 useMockData() 进行
↓
阶段二:创建真实API composable,保持相同接口
↓
阶段三:替换导入路径,移除 useMockData()
迁移示例
// 迁移前:使用Mock
import { useMockData } from '~/composables/useMockData'
const { fetchUsers } = useMockData()
// 迁移后:使用真实API
import { useUsersApi } from '~/composables/api/useUsersApi'
const { fetchUsers } = useUsersApi()
📁 文件结构规范
frontend/
├── src/
│ ├── composables/
│ │ ├── useMockData.ts # 主要Mock composable
│ │ └── api/ # 真实API composables(后期替换)
│ │ └── useUsersApi.ts
│ └── types/
│ └── api/ # API类型定义
│ └── user.ts
├── apiMock/ # Mock API服务器
│ ├── api/
│ │ ├── auth/
│ │ │ └── login.json
│ │ └── users/
│ │ └── index.json
│ └── README.md
└── tests/
├── setup/
│ ├── vitest.setup.ts # 测试全局设置
│ └── msw.ts # MSW处理器
└── unit/
└── composables/
└── useMockData.spec.ts
🧪 测试覆盖率要求
| 测试类型 | 覆盖率目标 | Mock策略 |
|---|---|---|
| 单元测试 | 行覆盖率≥80% | Mock API调用 |
| 集成测试 | 核心流程覆盖 | MSW模拟 |
| E2E测试 | 关键用户路径 | Playwright网络拦截 |
🔗 相关文档参考
核心文档
- 前端实现标准:
docs/guidelines/implementation/frontend.md - 前端单元测试指南:
docs/guidelines/testing/frontend-unittest-guidelines.md - 后端单元测试指南:
docs/guidelines/testing/backend-unittest-guidelines.md
实现教程
- Mock实现指南:
frontend/docs/guides/mock-implementation.md - 环境搭建指南:
frontend/docs/getting-started/installation.md
代码示例
- useMockData实现:
frontend/src/composables/useMockData.ts - Mock API示例:
frontend/apiMock/api/目录
🎯 快速参考速查卡
Mock数据创建流程
1. 确定API响应数据结构
2. 创建类型定义(types/api/xxx.ts)
3. 在useMockData.ts中添加Mock函数
4. 可选:在apiMock/中添加静态JSON
5. 在组件中使用Mock函数
6. 后期替换为真实API
常用Mock函数
// 获取数据
const users = await fetchUsers()
// 保存数据
const result = await saveData(userData)
// 搜索数据
const results = await searchData(keyword)
// 分页数据
const pageData = await fetchPaginatedData(1, 10)
环境切换
# 使用Mock数据
cross-env NUXT_MOCK_API_PROXY=1 npm run dev
# 使用真实API
cross-env NUXT_MOCK_API_PROXY=0 npm run dev
核心原则:Mock数据是开发效率工具,不是业务逻辑替代品。保持Mock数据与真实API的一致性,确保平滑迁移。
最后更新: 2026-02-04
适用项目: APJ-B2B前端项目
相关标准: Nuxt 3、TypeScript严格模式、MSW、Vitest