Skip to content

整理前文档快照:04.测试策略 ​

这是历史资料,不作为当前操作说明;返回现行页面。原文按文本保存,保留当时方案及验证范围。

text
# 测试策略

## 测试分层

```mermaid
graph TD
    E2E[E2E 测试] --> Integration[集成测试]
    Integration --> Unit[单元测试]
    Unit --> Static[静态检查]

    Static --> ESLint[ESLint]
    Static --> TSC[TypeScript 类型检查]
    Static --> Prettier[Prettier]
```

---

## 静态检查

### 后端

```bash
cd yunstack-backend
pnpm lint          # ESLint 检查
pnpm format        # Prettier 格式化
npx tsc --noEmit   # TypeScript 类型检查
```

### 前端

```bash
cd yunstack-web
pnpm lint:eslint   # ESLint
pnpm lint:prettier # Prettier
pnpm lint:stylelint # Stylelint
pnpm type-check    # TypeScript

cd yunstack-uniapp
pnpm lint:eslint
pnpm lint:prettier
pnpm lint:stylelint
pnpm type-check
```

---

## 单元测试

### 后端 (Jest)

```bash
cd yunstack-backend
pnpm test         # 运行全部测试
pnpm test:watch   # 监听模式
pnpm test:cov     # 覆盖率报告
```

**编写规范:**

```typescript
// user.service.spec.ts
import { Test, TestingModule } from '@nestjs/testing';
import { UserService } from './user.service';

describe('UserService', () => {
  let service: UserService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [UserService],
    }).compile();
    service = module.get<UserService>(UserService);
  });

  describe('findAll', () => {
    it('should return paginated users', async () => {
      const result = await service.findAll({ pageNum: 1, pageSize: 10 });
      expect(result.list).toBeDefined();
      expect(result.total).toBeGreaterThanOrEqual(0);
    });
  });
});
```

### 前端 (待实现)

```bash
cd yunstack-web
# 计划使用 Vitest
pnpm test
pnpm test:cov
```

---

## E2E 测试

### 后端 (Supertest)

```bash
cd yunstack-backend
pnpm test:e2e
```

```typescript
// test/auth.e2e-spec.ts
import * as request from 'supertest';

describe('Auth (e2e)', () => {
  it('/api/v1/auth/login (POST)', () => {
    return request(app.getHttpServer())
      .post('/api/v1/auth/login')
      .send({ username: 'admin', password: '123456' })
      .expect(201)
      .expect(res => {
        expect(res.body.code).toBe('00000');
      });
  });
});
```

---

## 测试覆盖率目标

| 层级 | 目标 | 说明 |
|------|------|------|
| Service 层 | ≥ 80% | 核心业务逻辑 |
| Controller 层 | ≥ 60% | 路由和参数校验 |
| 工具函数 | ≥ 90% | 纯函数易于测试 |
| E2E | 核心流程 | 登录、CRUD、设备通信 |

### 当前生效门槛(2026-09-11)

`package.json` 的 jest 配置中已启用 `coverageThreshold`,强制校验范围如下:

| Glob | 门槛 | 状态 |
|------|------|------|
| `**/modules/**/*.service.ts` | statements / lines ≥ 80% | ✅ 已达标 |
| `**/modules/**/*.controller.ts` | statements / lines ≥ 60% | ✅ 已达标 |
| `**/gateways/**/*.controller.ts` | statements / lines ≥ 60% | ✅ 已达标 |

**未纳入门槛的层级**(基础设施与网关服务,覆盖率仍偏低,需后续单独治理):Influx / Redis / Prisma、Cache / Mail、WebSocket Service。整体覆盖率(statements 57.46% / lines 57.57%)主要受这些层级拉低。

E2E 目前通过 HTTP 层用例执行:`pnpm test:e2e` → 7 套件 / 55 用例全部通过。

---

## 关键测试场景

### 后端必须测试

1. **认证流程**:登录成功/失败、Token 刷新、登出
2. **权限控制**:admin/普通用户访问权限边界
3. **CRUD 操作**:创建、查询、更新、删除的正确性
4. **参数校验**:必填字段、类型校验、边界值
5. **MQTT 消息处理**:消息解析、Topic 匹配

### 前端必须测试

1. **登录流程**:表单验证、Token 存储、路由跳转
2. **权限路由**:角色路由过滤
3. **列表页面**:分页、搜索、排序

---

## CI/CD 集成

```yaml
# 未来 GitHub Actions 参考
- name: Lint
  run: pnpm lint
- name: Type Check
  run: pnpm type-check
- name: Unit Test
  run: pnpm test:cov
- name: Build
  run: pnpm build
```