|
|
@@ -3,6 +3,7 @@
|
|
|
## 版本信息
|
|
|
| 版本 | 日期 | 描述 | 作者 |
|
|
|
|------|------|------|------|
|
|
|
+| 4.0 | 2025-10-31 | 基于实际测试结构更新Taro小程序测试策略,添加最新测试模式 | Winston |
|
|
|
| 3.2 | 2025-10-20 | 修正Taro测试工具引用,更新为实际使用的测试框架 | Winston |
|
|
|
| 3.1 | 2025-10-16 | 修正测试路径描述,更新Taro测试说明 | Winston |
|
|
|
| 3.0 | 2025-10-15 | 更新为出行服务项目测试策略 | Winston |
|
|
|
@@ -50,31 +51,44 @@
|
|
|
|
|
|
### Taro小程序测试体系 (独立项目)
|
|
|
|
|
|
-**注意**: Taro小程序项目位于 `mini/` 目录,是独立的项目结构,拥有自己的测试配置和运行方式。
|
|
|
+**注意**: Taro小程序项目位于 `mini/` 目录,是独立的项目结构,拥有自己的测试配置和运行方式。基于实际测试结构分析,当前测试体系如下:
|
|
|
|
|
|
#### 组件测试 (Component Tests)
|
|
|
- **范围**: Taro小程序组件
|
|
|
- **目标**: 验证组件渲染和交互行为
|
|
|
-- **位置**: `mini/tests/**/*.test.{ts,tsx}`
|
|
|
+- **位置**: `mini/tests/components/**/*.test.{ts,tsx}`
|
|
|
- **框架**: Jest + @testing-library/react + 自定义Taro组件mock
|
|
|
- **覆盖率目标**: ≥ 70%
|
|
|
- **执行频率**: 每次组件变更
|
|
|
+- **示例文件**: [Button.test.tsx](mini/tests/components/Button.test.tsx)
|
|
|
|
|
|
#### 页面测试 (Page Tests)
|
|
|
-- **范围**: 小程序页面级测试
|
|
|
-- **目标**: 验证页面生命周期和路由
|
|
|
+- **范围**: 小程序页面级测试,包含完整业务逻辑
|
|
|
+- **目标**: 验证页面生命周期、路由、状态管理和API集成
|
|
|
- **位置**: `mini/tests/pages/**/*.test.{ts,tsx}`
|
|
|
-- **框架**: Jest + @testing-library/react + 自定义Taro组件mock
|
|
|
+- **框架**: Jest + @testing-library/react + React Query + Taro API mock
|
|
|
- **覆盖率目标**: ≥ 60%
|
|
|
- **执行频率**: 每次页面变更
|
|
|
+- **最新示例**:
|
|
|
+ - [order-page.test.tsx](mini/tests/pages/order-page.test.tsx) - 订单页面完整测试
|
|
|
+ - [profile.test.tsx](mini/tests/pages/profile.test.tsx) - 个人中心页面测试
|
|
|
+
|
|
|
+#### 单元测试 (Unit Tests)
|
|
|
+- **范围**: 工具函数、业务逻辑、状态管理
|
|
|
+- **目标**: 验证独立业务逻辑单元的正确性
|
|
|
+- **位置**: `mini/tests/unit/**/*.test.{ts,tsx}`
|
|
|
+- **框架**: Jest + 自定义测试工具
|
|
|
+- **覆盖率目标**: ≥ 80%
|
|
|
+- **执行频率**: 每次业务逻辑变更
|
|
|
+- **示例文件**: [payment.test.ts](mini/tests/unit/payment.test.ts)
|
|
|
|
|
|
-#### 多端测试 (Multi-Platform Tests)
|
|
|
-- **范围**: 不同小程序平台测试
|
|
|
-- **目标**: 验证多端兼容性
|
|
|
-- **位置**: `mini/tests/platforms/**/*.test.{ts,tsx}`
|
|
|
-- **框架**: Jest + 环境变量区分平台
|
|
|
-- **覆盖率目标**: 关键功能100%
|
|
|
-- **执行频率**: 每次平台相关变更
|
|
|
+#### 测试基础设施
|
|
|
+- **测试配置**: `mini/tests/setup.ts` - 完整的Taro组件和API mock
|
|
|
+- **测试工具**: `mini/tests/utils.ts` - 测试辅助函数和mock数据生成器
|
|
|
+- **Mock文件**: `mini/tests/__mocks__/` - Taro API和组件mock
|
|
|
+ - `taroMock.ts` - 统一的Taro API mock,包含所有常用API
|
|
|
+ - `taroMock.ts` - 通过jest.config.js的moduleNameMapper重定向@tarojs/taro
|
|
|
+- **快照**: `mini/tests/__snapshots__/` - UI快照测试
|
|
|
|
|
|
## 测试环境配置
|
|
|
|
|
|
@@ -211,16 +225,20 @@ npm run test:coverage
|
|
|
cd mini
|
|
|
|
|
|
# 运行所有Taro测试
|
|
|
-npm test
|
|
|
+pnpm test
|
|
|
|
|
|
# 运行H5环境测试
|
|
|
-npm run test:h5
|
|
|
+pnpm run test:h5
|
|
|
|
|
|
# 运行微信小程序环境测试
|
|
|
-npm run test:weapp
|
|
|
+pnpm run test:weapp
|
|
|
|
|
|
# 生成覆盖率报告
|
|
|
-npm run test:coverage
|
|
|
+pnpm run test:coverage
|
|
|
+
|
|
|
+# 运行特定测试文件
|
|
|
+pnpm test -- order-page.test.tsx
|
|
|
+pnpm test -- profile.test.tsx
|
|
|
```
|
|
|
|
|
|
### CI/CD流水线测试
|
|
|
@@ -274,43 +292,117 @@ npm run test:coverage
|
|
|
- **autocannon**: API性能测试
|
|
|
- **Playwright**: E2E性能监控
|
|
|
|
|
|
-## 测试文档标准
|
|
|
+## 最新测试模式和最佳实践
|
|
|
+
|
|
|
+### Taro小程序测试模式
|
|
|
+
|
|
|
+#### 页面级集成测试模式
|
|
|
+基于最新的 [order-page.test.tsx](mini/tests/pages/order-page.test.tsx) 和 [profile.test.tsx](mini/tests/pages/profile.test.tsx) 测试文件,推荐以下测试模式:
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 1. 完整的测试环境设置
|
|
|
+const createTestQueryClient = () => new QueryClient({
|
|
|
+ defaultOptions: {
|
|
|
+ queries: { retry: false },
|
|
|
+ },
|
|
|
+})
|
|
|
+
|
|
|
+// 2. 组件包装器
|
|
|
+const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
|
|
+ <QueryClientProvider client={createTestQueryClient()}>
|
|
|
+ {children}
|
|
|
+ </QueryClientProvider>
|
|
|
+)
|
|
|
+
|
|
|
+// 3. 完整的Mock策略 - 使用统一的taroMock
|
|
|
+import taroMock from '../../tests/__mocks__/taroMock'
|
|
|
+
|
|
|
+// 在测试中直接使用导入的mock函数
|
|
|
+taroMock.showToast.mockClear()
|
|
|
+taroMock.navigateTo.mockClear()
|
|
|
+
|
|
|
+// 4. 测试数据工厂
|
|
|
+const mockRouteData = {
|
|
|
+ id: 1,
|
|
|
+ name: '测试路线',
|
|
|
+ price: 100,
|
|
|
+ vehicleType: '商务车'
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 业务逻辑测试覆盖
|
|
|
+- **订单流程**: 支付验证、乘客管理、价格计算
|
|
|
+- **用户交互**: 按钮点击、表单验证、状态切换
|
|
|
+- **API集成**: React Query hooks、错误处理、加载状态
|
|
|
+- **多端兼容**: H5和小程序环境适配
|
|
|
+
|
|
|
+#### Mock策略说明
|
|
|
+- **统一Mock**: 使用 `taroMock.ts` 统一管理所有Taro API mock
|
|
|
+- **模块重定向**: 通过jest.config.js的moduleNameMapper将@tarojs/taro重定向到taroMock
|
|
|
+- **函数级控制**: 每个mock函数都可以独立控制和验证调用情况
|
|
|
|
|
|
### 测试代码规范
|
|
|
```typescript
|
|
|
-// 良好的测试示例
|
|
|
-describe('UserService', () => {
|
|
|
- describe('createUser()', () => {
|
|
|
- it('应该创建新用户并返回用户对象', async () => {
|
|
|
- // Arrange
|
|
|
- const userData = { username: 'testuser', email: 'test@example.com' };
|
|
|
-
|
|
|
- // Act
|
|
|
- const result = await userService.createUser(userData);
|
|
|
-
|
|
|
- // Assert
|
|
|
- expect(result).toHaveProperty('id');
|
|
|
- expect(result.username).toBe('testuser');
|
|
|
- expect(result.email).toBe('test@example.com');
|
|
|
- });
|
|
|
-
|
|
|
- it('应该拒绝重复的用户名', async () => {
|
|
|
- // Arrange
|
|
|
- const existingUser = await createTestUser({ username: 'existing' });
|
|
|
-
|
|
|
- // Act & Assert
|
|
|
- await expect(
|
|
|
- userService.createUser({ username: 'existing', email: 'new@example.com' })
|
|
|
- ).rejects.toThrow('用户名已存在');
|
|
|
- });
|
|
|
- });
|
|
|
-});
|
|
|
+// 良好的测试示例 - 基于最新测试文件
|
|
|
+describe('OrderPage', () => {
|
|
|
+ beforeEach(() => {
|
|
|
+ jest.clearAllMocks()
|
|
|
+ // 设置测试数据
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该正确渲染订单页面', () => {
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(screen.getByTestId('order-navbar')).toBeInTheDocument()
|
|
|
+ expect(screen.getByTestId('activity-name')).toHaveTextContent('测试活动')
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该处理支付验证逻辑', async () => {
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ const payButton = screen.getByTestId('pay-button')
|
|
|
+ fireEvent.click(payButton)
|
|
|
+
|
|
|
+ await waitFor(() => {
|
|
|
+ expect(taroMock.showToast).toHaveBeenCalledWith({
|
|
|
+ title: '请先获取手机号',
|
|
|
+ icon: 'none',
|
|
|
+ duration: 2000
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ it('应该处理不同出行模式', () => {
|
|
|
+ // 测试拼车和包车模式
|
|
|
+ mockUseRouter.mockReturnValue({
|
|
|
+ params: { type: 'carpool' }
|
|
|
+ })
|
|
|
+
|
|
|
+ render(
|
|
|
+ <Wrapper>
|
|
|
+ <OrderPage />
|
|
|
+ </Wrapper>
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(screen.getByTestId('service-type')).toHaveTextContent('班次信息')
|
|
|
+ })
|
|
|
+})
|
|
|
```
|
|
|
|
|
|
### 测试命名约定
|
|
|
-- **文件名**: `[module].test.ts` 或 `[module].integration.test.ts`
|
|
|
+- **文件名**: `[page/component].test.tsx` 或 `[feature].test.ts`
|
|
|
- **描述**: 使用「应该...」格式描述测试行为
|
|
|
- **用例**: 明确描述测试场景和预期结果
|
|
|
+- **测试数据**: 使用工厂函数创建测试数据
|
|
|
+- **Mock策略**: 完整的API和组件mock覆盖
|
|
|
|
|
|
## 监控和报告
|
|
|
|
|
|
@@ -338,10 +430,14 @@ describe('UserService', () => {
|
|
|
- **Testing Library**: 16.3.0
|
|
|
- **Playwright**: 1.55.0
|
|
|
- **hono/testing**: 内置(Hono 4.8.5)
|
|
|
+- **Jest**: 29.7.0 (Taro小程序)
|
|
|
+- **React Testing Library**: 16.3.0 (Taro小程序)
|
|
|
+- **React Query**: 5.8.4 (Taro小程序)
|
|
|
|
|
|
### 更新日志
|
|
|
| 日期 | 版本 | 描述 |
|
|
|
|------|------|------|
|
|
|
+| 2025-10-31 | 4.0 | 基于实际测试结构更新Taro小程序测试策略,添加最新测试模式 |
|
|
|
| 2025-10-20 | 3.2 | 修正Taro测试工具引用,更新为实际使用的测试框架 |
|
|
|
| 2025-10-16 | 3.1 | 修正测试路径描述,更新Taro测试说明 |
|
|
|
| 2025-10-15 | 3.0 | 更新为出行服务项目测试策略 |
|
|
|
@@ -353,4 +449,4 @@ describe('UserService', () => {
|
|
|
---
|
|
|
|
|
|
**文档状态**: 正式版
|
|
|
-**下次评审**: 2025-12-19
|
|
|
+**下次评审**: 2025-12-31
|