570 lines
11 KiB
Markdown
570 lines
11 KiB
Markdown
|
|
# 宁夏智慧养殖监管平台 测试文档
|
|||
|
|
|
|||
|
|
## 版本历史
|
|||
|
|
|
|||
|
|
| 版本 | 日期 | 作者 | 描述 |
|
|||
|
|
|------|------|------|------|
|
|||
|
|
| v1.0 | 2025-01-20 | 测试团队 | 初始版本 |
|
|||
|
|
|
|||
|
|
## 1. 测试概述
|
|||
|
|
|
|||
|
|
### 1.1 测试目标
|
|||
|
|
|
|||
|
|
本文档旨在为宁夏智慧养殖监管平台提供全面的测试指导,确保系统的功能性、性能、安全性和可靠性满足产品需求。
|
|||
|
|
|
|||
|
|
### 1.2 测试范围
|
|||
|
|
|
|||
|
|
**包含的测试内容:**
|
|||
|
|
- 前端应用测试(Vue 3 + Vite)
|
|||
|
|
- 后端API测试(Node.js + Express)
|
|||
|
|
- 数据库测试(MySQL)
|
|||
|
|
- 小程序测试(uni-app)
|
|||
|
|
- 集成测试
|
|||
|
|
- 性能测试
|
|||
|
|
- 安全测试
|
|||
|
|
|
|||
|
|
**不包含的测试内容:**
|
|||
|
|
- 第三方服务测试(百度地图API等)
|
|||
|
|
- 硬件设备测试
|
|||
|
|
- 网络基础设施测试
|
|||
|
|
|
|||
|
|
## 2. 测试策略
|
|||
|
|
|
|||
|
|
### 2.1 测试类型
|
|||
|
|
|
|||
|
|
#### 2.1.1 单元测试
|
|||
|
|
- **目标覆盖率**: ≥80%
|
|||
|
|
- **测试框架**: Jest (后端), Vitest (前端)
|
|||
|
|
- **测试内容**: 函数、组件、工具类
|
|||
|
|
- **执行频率**: 每次代码提交
|
|||
|
|
|
|||
|
|
#### 2.1.2 集成测试
|
|||
|
|
- **测试框架**: Supertest (API), Vue Test Utils (组件)
|
|||
|
|
- **测试内容**: API接口、组件交互、数据流
|
|||
|
|
- **执行频率**: 每日构建
|
|||
|
|
|
|||
|
|
#### 2.1.3 端到端测试
|
|||
|
|
- **测试框架**: Cypress
|
|||
|
|
- **测试内容**: 完整业务流程、用户交互
|
|||
|
|
- **执行频率**: 版本发布前
|
|||
|
|
|
|||
|
|
#### 2.1.4 性能测试
|
|||
|
|
- **测试工具**: Jest (单元性能), 自定义脚本
|
|||
|
|
- **测试内容**: 响应时间、并发处理、资源使用
|
|||
|
|
- **执行频率**: 版本发布前
|
|||
|
|
|
|||
|
|
### 2.2 测试环境
|
|||
|
|
|
|||
|
|
#### 2.2.1 开发环境
|
|||
|
|
- **用途**: 开发人员自测
|
|||
|
|
- **数据**: 模拟数据
|
|||
|
|
- **配置**: 本地开发配置
|
|||
|
|
|
|||
|
|
#### 2.2.2 测试环境
|
|||
|
|
- **用途**: QA团队测试
|
|||
|
|
- **数据**: 测试数据集
|
|||
|
|
- **配置**: 接近生产环境
|
|||
|
|
|
|||
|
|
#### 2.2.3 预生产环境
|
|||
|
|
- **用途**: 用户验收测试
|
|||
|
|
- **数据**: 生产数据副本
|
|||
|
|
- **配置**: 生产环境配置
|
|||
|
|
|
|||
|
|
## 3. 测试工具和框架
|
|||
|
|
|
|||
|
|
### 3.1 后端测试工具
|
|||
|
|
|
|||
|
|
#### 3.1.1 Jest 配置
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"testEnvironment": "node",
|
|||
|
|
"collectCoverageFrom": [
|
|||
|
|
"controllers/**/*.js",
|
|||
|
|
"models/**/*.js",
|
|||
|
|
"routes/**/*.js",
|
|||
|
|
"utils/**/*.js",
|
|||
|
|
"!**/node_modules/**",
|
|||
|
|
"!**/migrations/**",
|
|||
|
|
"!**/seeds/**"
|
|||
|
|
],
|
|||
|
|
"coverageDirectory": "coverage",
|
|||
|
|
"coverageReporters": ["text", "lcov", "html"]
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.1.2 Supertest API测试
|
|||
|
|
```javascript
|
|||
|
|
const request = require('supertest');
|
|||
|
|
const app = require('../app');
|
|||
|
|
|
|||
|
|
describe('API Tests', () => {
|
|||
|
|
test('GET /api/farms', async () => {
|
|||
|
|
const response = await request(app)
|
|||
|
|
.get('/api/farms')
|
|||
|
|
.expect(200);
|
|||
|
|
|
|||
|
|
expect(response.body).toHaveProperty('data');
|
|||
|
|
expect(Array.isArray(response.body.data)).toBe(true);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.2 前端测试工具
|
|||
|
|
|
|||
|
|
#### 3.2.1 Vitest 配置
|
|||
|
|
```typescript
|
|||
|
|
import { defineConfig } from 'vitest/config'
|
|||
|
|
import vue from '@vitejs/plugin-vue'
|
|||
|
|
|
|||
|
|
export default defineConfig({
|
|||
|
|
plugins: [vue()],
|
|||
|
|
test: {
|
|||
|
|
environment: 'jsdom',
|
|||
|
|
coverage: {
|
|||
|
|
reporter: ['text', 'json', 'html']
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 3.2.2 Vue Test Utils 组件测试
|
|||
|
|
```typescript
|
|||
|
|
import { mount } from '@vue/test-utils'
|
|||
|
|
import StatusTag from '@/components/StatusTag.vue'
|
|||
|
|
|
|||
|
|
describe('StatusTag.vue', () => {
|
|||
|
|
it('renders correctly', () => {
|
|||
|
|
const wrapper = mount(StatusTag, {
|
|||
|
|
props: {
|
|||
|
|
status: 'success',
|
|||
|
|
text: '正常'
|
|||
|
|
}
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
expect(wrapper.text()).toContain('正常')
|
|||
|
|
expect(wrapper.classes()).toContain('status-success')
|
|||
|
|
})
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3.3 小程序测试工具
|
|||
|
|
|
|||
|
|
#### 3.3.1 uni-app 测试配置
|
|||
|
|
```typescript
|
|||
|
|
// jest.config.ts
|
|||
|
|
export default {
|
|||
|
|
preset: 'ts-jest',
|
|||
|
|
testEnvironment: 'jsdom',
|
|||
|
|
moduleNameMapping: {
|
|||
|
|
'^@/(.*)$': '<rootDir>/src/$1'
|
|||
|
|
},
|
|||
|
|
transform: {
|
|||
|
|
'^.+\\.vue$': '@vue/vue3-jest'
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 4. 测试用例设计
|
|||
|
|
|
|||
|
|
### 4.1 功能测试用例
|
|||
|
|
|
|||
|
|
#### 4.1.1 用户认证测试
|
|||
|
|
```javascript
|
|||
|
|
describe('用户认证', () => {
|
|||
|
|
test('正确的用户名密码应该登录成功', async () => {
|
|||
|
|
const loginData = {
|
|||
|
|
username: 'testuser',
|
|||
|
|
password: 'testpass123'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const response = await request(app)
|
|||
|
|
.post('/api/auth/login')
|
|||
|
|
.send(loginData)
|
|||
|
|
.expect(200);
|
|||
|
|
|
|||
|
|
expect(response.body).toHaveProperty('token');
|
|||
|
|
expect(response.body.user.username).toBe('testuser');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('错误的密码应该返回401', async () => {
|
|||
|
|
const loginData = {
|
|||
|
|
username: 'testuser',
|
|||
|
|
password: 'wrongpass'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
await request(app)
|
|||
|
|
.post('/api/auth/login')
|
|||
|
|
.send(loginData)
|
|||
|
|
.expect(401);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 4.1.2 数据CRUD测试
|
|||
|
|
```javascript
|
|||
|
|
describe('养殖场管理', () => {
|
|||
|
|
let farmId;
|
|||
|
|
|
|||
|
|
test('创建养殖场', async () => {
|
|||
|
|
const farmData = {
|
|||
|
|
name: '测试养殖场',
|
|||
|
|
location: '宁夏银川',
|
|||
|
|
type: 'cattle'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const response = await request(app)
|
|||
|
|
.post('/api/farms')
|
|||
|
|
.send(farmData)
|
|||
|
|
.expect(201);
|
|||
|
|
|
|||
|
|
farmId = response.body.data.id;
|
|||
|
|
expect(response.body.data.name).toBe('测试养殖场');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('获取养殖场列表', async () => {
|
|||
|
|
const response = await request(app)
|
|||
|
|
.get('/api/farms')
|
|||
|
|
.expect(200);
|
|||
|
|
|
|||
|
|
expect(Array.isArray(response.body.data)).toBe(true);
|
|||
|
|
expect(response.body.data.length).toBeGreaterThan(0);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('更新养殖场信息', async () => {
|
|||
|
|
const updateData = {
|
|||
|
|
name: '更新后的养殖场'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const response = await request(app)
|
|||
|
|
.put(`/api/farms/${farmId}`)
|
|||
|
|
.send(updateData)
|
|||
|
|
.expect(200);
|
|||
|
|
|
|||
|
|
expect(response.body.data.name).toBe('更新后的养殖场');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('删除养殖场', async () => {
|
|||
|
|
await request(app)
|
|||
|
|
.delete(`/api/farms/${farmId}`)
|
|||
|
|
.expect(204);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.2 性能测试用例
|
|||
|
|
|
|||
|
|
#### 4.2.1 响应时间测试
|
|||
|
|
```javascript
|
|||
|
|
describe('性能测试', () => {
|
|||
|
|
test('API响应时间应小于500ms', async () => {
|
|||
|
|
const startTime = Date.now();
|
|||
|
|
|
|||
|
|
await request(app)
|
|||
|
|
.get('/api/farms')
|
|||
|
|
.expect(200);
|
|||
|
|
|
|||
|
|
const responseTime = Date.now() - startTime;
|
|||
|
|
expect(responseTime).toBeLessThan(500);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('并发请求处理', async () => {
|
|||
|
|
const promises = [];
|
|||
|
|
|
|||
|
|
for (let i = 0; i < 10; i++) {
|
|||
|
|
promises.push(
|
|||
|
|
request(app)
|
|||
|
|
.get('/api/farms')
|
|||
|
|
.expect(200)
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const results = await Promise.all(promises);
|
|||
|
|
expect(results.length).toBe(10);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4.3 安全测试用例
|
|||
|
|
|
|||
|
|
#### 4.3.1 输入验证测试
|
|||
|
|
```javascript
|
|||
|
|
describe('安全测试', () => {
|
|||
|
|
test('SQL注入防护', async () => {
|
|||
|
|
const maliciousInput = {
|
|||
|
|
name: "'; DROP TABLE farms; --"
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
await request(app)
|
|||
|
|
.post('/api/farms')
|
|||
|
|
.send(maliciousInput)
|
|||
|
|
.expect(400);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
test('XSS防护', async () => {
|
|||
|
|
const xssInput = {
|
|||
|
|
name: '<script>alert("xss")</script>'
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const response = await request(app)
|
|||
|
|
.post('/api/farms')
|
|||
|
|
.send(xssInput)
|
|||
|
|
.expect(201);
|
|||
|
|
|
|||
|
|
expect(response.body.data.name).not.toContain('<script>');
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 5. 测试执行
|
|||
|
|
|
|||
|
|
### 5.1 测试命令
|
|||
|
|
|
|||
|
|
#### 5.1.1 后端测试
|
|||
|
|
```bash
|
|||
|
|
# 运行所有测试
|
|||
|
|
npm test
|
|||
|
|
|
|||
|
|
# 运行单元测试
|
|||
|
|
npm run test:unit
|
|||
|
|
|
|||
|
|
# 运行集成测试
|
|||
|
|
npm run test:integration
|
|||
|
|
|
|||
|
|
# 生成覆盖率报告
|
|||
|
|
npm run test:coverage
|
|||
|
|
|
|||
|
|
# 监听模式
|
|||
|
|
npm run test:watch
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 5.1.2 前端测试
|
|||
|
|
```bash
|
|||
|
|
# 运行所有测试
|
|||
|
|
npm run test
|
|||
|
|
|
|||
|
|
# 运行单元测试
|
|||
|
|
npm run test:unit
|
|||
|
|
|
|||
|
|
# 运行端到端测试
|
|||
|
|
npm run test:e2e
|
|||
|
|
|
|||
|
|
# 生成覆盖率报告
|
|||
|
|
npm run test:coverage
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 5.1.3 小程序测试
|
|||
|
|
```bash
|
|||
|
|
# 运行测试
|
|||
|
|
npm run test
|
|||
|
|
|
|||
|
|
# 监听模式
|
|||
|
|
npm run test:watch
|
|||
|
|
|
|||
|
|
# 覆盖率报告
|
|||
|
|
npm run test:coverage
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5.2 持续集成
|
|||
|
|
|
|||
|
|
#### 5.2.1 GitHub Actions 配置
|
|||
|
|
```yaml
|
|||
|
|
name: Test Suite
|
|||
|
|
on: [push, pull_request]
|
|||
|
|
|
|||
|
|
jobs:
|
|||
|
|
test:
|
|||
|
|
runs-on: ubuntu-latest
|
|||
|
|
|
|||
|
|
services:
|
|||
|
|
mysql:
|
|||
|
|
image: mysql:8.0
|
|||
|
|
env:
|
|||
|
|
MYSQL_ROOT_PASSWORD: testpass
|
|||
|
|
MYSQL_DATABASE: test_db
|
|||
|
|
ports:
|
|||
|
|
- 3306:3306
|
|||
|
|
|
|||
|
|
steps:
|
|||
|
|
- uses: actions/checkout@v2
|
|||
|
|
|
|||
|
|
- name: Setup Node.js
|
|||
|
|
uses: actions/setup-node@v2
|
|||
|
|
with:
|
|||
|
|
node-version: '18'
|
|||
|
|
|
|||
|
|
- name: Install dependencies
|
|||
|
|
run: npm ci
|
|||
|
|
|
|||
|
|
- name: Run tests
|
|||
|
|
run: npm test
|
|||
|
|
|
|||
|
|
- name: Upload coverage
|
|||
|
|
uses: codecov/codecov-action@v2
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 6. 测试数据管理
|
|||
|
|
|
|||
|
|
### 6.1 测试数据准备
|
|||
|
|
|
|||
|
|
#### 6.1.1 种子数据
|
|||
|
|
```javascript
|
|||
|
|
// seeds/test-data.js
|
|||
|
|
module.exports = {
|
|||
|
|
farms: [
|
|||
|
|
{
|
|||
|
|
id: 1,
|
|||
|
|
name: '测试养殖场1',
|
|||
|
|
location: '宁夏银川',
|
|||
|
|
type: 'cattle',
|
|||
|
|
status: 'active'
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
id: 2,
|
|||
|
|
name: '测试养殖场2',
|
|||
|
|
location: '宁夏石嘴山',
|
|||
|
|
type: 'sheep',
|
|||
|
|
status: 'active'
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
users: [
|
|||
|
|
{
|
|||
|
|
id: 1,
|
|||
|
|
username: 'testuser',
|
|||
|
|
email: 'test@example.com',
|
|||
|
|
role: 'admin'
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 6.1.2 数据清理
|
|||
|
|
```javascript
|
|||
|
|
// 测试前清理数据
|
|||
|
|
beforeEach(async () => {
|
|||
|
|
await Farm.destroy({ where: {} });
|
|||
|
|
await User.destroy({ where: {} });
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 测试后清理数据
|
|||
|
|
afterEach(async () => {
|
|||
|
|
await Farm.destroy({ where: {} });
|
|||
|
|
await User.destroy({ where: {} });
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 6.2 Mock数据
|
|||
|
|
|
|||
|
|
#### 6.2.1 API Mock
|
|||
|
|
```javascript
|
|||
|
|
// __mocks__/api.js
|
|||
|
|
export const mockFarmData = {
|
|||
|
|
id: 1,
|
|||
|
|
name: '模拟养殖场',
|
|||
|
|
location: '宁夏银川',
|
|||
|
|
animals: 100
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export const getFarms = jest.fn(() =>
|
|||
|
|
Promise.resolve({ data: [mockFarmData] })
|
|||
|
|
);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 7. 测试报告
|
|||
|
|
|
|||
|
|
### 7.1 覆盖率报告
|
|||
|
|
|
|||
|
|
测试覆盖率目标:
|
|||
|
|
- **整体覆盖率**: ≥80%
|
|||
|
|
- **函数覆盖率**: ≥85%
|
|||
|
|
- **分支覆盖率**: ≥75%
|
|||
|
|
- **行覆盖率**: ≥80%
|
|||
|
|
|
|||
|
|
### 7.2 测试结果分析
|
|||
|
|
|
|||
|
|
#### 7.2.1 成功标准
|
|||
|
|
- 所有测试用例通过
|
|||
|
|
- 覆盖率达到目标要求
|
|||
|
|
- 性能测试满足要求
|
|||
|
|
- 安全测试无漏洞
|
|||
|
|
|
|||
|
|
#### 7.2.2 失败处理
|
|||
|
|
- 记录失败原因
|
|||
|
|
- 分析根本原因
|
|||
|
|
- 修复问题
|
|||
|
|
- 重新执行测试
|
|||
|
|
|
|||
|
|
## 8. 最佳实践
|
|||
|
|
|
|||
|
|
### 8.1 测试编写原则
|
|||
|
|
|
|||
|
|
1. **独立性**: 测试用例之间相互独立
|
|||
|
|
2. **可重复性**: 测试结果可重复
|
|||
|
|
3. **快速执行**: 单元测试执行时间短
|
|||
|
|
4. **清晰命名**: 测试名称描述清楚
|
|||
|
|
5. **边界测试**: 包含边界值测试
|
|||
|
|
|
|||
|
|
### 8.2 测试维护
|
|||
|
|
|
|||
|
|
1. **定期更新**: 随代码变更更新测试
|
|||
|
|
2. **重构测试**: 消除重复代码
|
|||
|
|
3. **性能优化**: 提高测试执行效率
|
|||
|
|
4. **文档更新**: 保持测试文档最新
|
|||
|
|
|
|||
|
|
## 9. 故障排除
|
|||
|
|
|
|||
|
|
### 9.1 常见问题
|
|||
|
|
|
|||
|
|
#### 9.1.1 测试环境问题
|
|||
|
|
- 数据库连接失败
|
|||
|
|
- 依赖服务不可用
|
|||
|
|
- 环境变量配置错误
|
|||
|
|
|
|||
|
|
#### 9.1.2 测试用例问题
|
|||
|
|
- 异步测试超时
|
|||
|
|
- Mock数据不正确
|
|||
|
|
- 测试数据污染
|
|||
|
|
|
|||
|
|
### 9.2 解决方案
|
|||
|
|
|
|||
|
|
#### 9.2.1 环境检查
|
|||
|
|
```bash
|
|||
|
|
# 检查数据库连接
|
|||
|
|
npm run test:db-connection
|
|||
|
|
|
|||
|
|
# 检查服务状态
|
|||
|
|
npm run test:services
|
|||
|
|
|
|||
|
|
# 验证环境配置
|
|||
|
|
npm run test:config
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 9.2.2 调试技巧
|
|||
|
|
```javascript
|
|||
|
|
// 使用调试模式
|
|||
|
|
describe.only('特定测试', () => {
|
|||
|
|
// 只运行这个测试套件
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 跳过测试
|
|||
|
|
test.skip('暂时跳过的测试', () => {
|
|||
|
|
// 这个测试不会执行
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 10. 联系信息
|
|||
|
|
|
|||
|
|
### 10.1 测试团队
|
|||
|
|
- **测试负责人**: 张三 (zhang.san@nxxmdata.com)
|
|||
|
|
- **自动化测试**: 李四 (li.si@nxxmdata.com)
|
|||
|
|
- **性能测试**: 王五 (wang.wu@nxxmdata.com)
|
|||
|
|
|
|||
|
|
### 10.2 支持渠道
|
|||
|
|
- **邮箱**: test-support@nxxmdata.com
|
|||
|
|
- **Slack**: #testing-support
|
|||
|
|
- **工作时间**: 周一至周五 9:00-18:00
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**最后更新**: 2025年1月20日
|
|||
|
|
**文档版本**: v1.0
|
|||
|
|
**维护团队**: 宁夏智慧养殖平台测试团队
|