# 测试文档
## 版本历史
| 版本 | 日期 | 作者 | 变更说明 |
|------|------|------|----------|
| 1.0 | 2024-01-20 | 测试团队 | 初始版本 |
| 1.1 | 2024-09-21 | 测试团队 | 更新测试策略,与实际项目保持一致 |
## 1. 测试概述
### 1.1 测试目标
确保畜牧养殖管理平台的功能完整性、性能稳定性、安全可靠性,为用户提供高质量的软件产品。
### 1.2 测试范围
- **功能测试**:验证系统功能是否符合需求规格说明
- **性能测试**:验证系统在各种负载下的性能表现
- **安全测试**:验证系统的安全防护能力
- **兼容性测试**:验证系统在不同环境下的兼容性
- **用户体验测试**:验证系统的易用性和用户体验
### 1.3 测试策略
采用分层测试策略,包括单元测试、集成测试、系统测试和验收测试。
```mermaid
graph TD
A[验收测试] --> B[系统测试]
B --> C[集成测试]
C --> D[单元测试]
D --> D1[前端单元测试]
D --> D2[后端单元测试]
D --> D3[小程序单元测试]
C --> C1[API集成测试]
C --> C2[数据库集成测试]
C --> C3[第三方服务集成测试]
B --> B1[功能测试]
B --> B2[性能测试]
B --> B3[安全测试]
A --> A1[用户验收测试]
A --> A2[业务验收测试]
```
## 2. 测试环境
### 2.1 测试环境配置
| 环境类型 | 服务器配置 | 数据库 | 域名 | 用途 |
|----------|------------|--------|------|------|
| 开发测试环境 | 2核4G | MySQL 8.0 | dev-test.xlxumu.com | 开发阶段测试 |
| 集成测试环境 | 4核8G | MySQL 8.0 + Redis | test.xlxumu.com | 集成测试 |
| 性能测试环境 | 8核16G | MySQL 8.0 + Redis | perf.xlxumu.com | 性能测试 |
| 预生产环境 | 8核16G | MySQL 8.0 + Redis | pre.xlxumu.com | 生产前验证 |
### 2.2 测试数据准备
```sql
-- 测试数据初始化脚本
-- 用户测试数据
INSERT INTO users (username, password, role, status) VALUES
('test_admin', 'hashed_password', 'admin', 'active'),
('test_farmer', 'hashed_password', 'farmer', 'active'),
('test_trader', 'hashed_password', 'trader', 'active');
-- 养殖场测试数据
INSERT INTO farms (name, owner_id, location, area, status) VALUES
('测试养殖场1', 1, '北京市朝阳区', 1000, 'active'),
('测试养殖场2', 2, '河北省承德市', 2000, 'active');
-- 动物测试数据
INSERT INTO animals (farm_id, breed, birth_date, gender, status) VALUES
(1, '安格斯牛', '2023-01-15', 'male', 'healthy'),
(1, '西门塔尔牛', '2023-02-20', 'female', 'healthy'),
(2, '夏洛莱牛', '2023-03-10', 'male', 'healthy');
```
## 3. 单元测试
### 3.1 前端单元测试
#### 3.1.1 Vue组件测试
```javascript
// tests/unit/components/AnimalCard.spec.js
import { mount } from '@vue/test-utils'
import AnimalCard from '@/components/AnimalCard.vue'
describe('AnimalCard.vue', () => {
it('renders animal information correctly', () => {
const animal = {
id: 1,
breed: '安格斯牛',
age: 12,
weight: 450,
status: 'healthy'
}
const wrapper = mount(AnimalCard, {
props: { animal }
})
expect(wrapper.text()).toContain('安格斯牛')
expect(wrapper.text()).toContain('12')
expect(wrapper.text()).toContain('450')
expect(wrapper.find('.status-healthy')).toBeTruthy()
})
it('emits edit event when edit button clicked', async () => {
const animal = { id: 1, breed: '安格斯牛' }
const wrapper = mount(AnimalCard, {
props: { animal }
})
await wrapper.find('.edit-btn').trigger('click')
expect(wrapper.emitted().edit).toBeTruthy()
expect(wrapper.emitted().edit[0]).toEqual([animal])
})
})
```
#### 3.1.2 Vuex Store测试
```javascript
// tests/unit/store/animals.spec.js
import { createStore } from 'vuex'
import animalsModule from '@/store/modules/animals'
describe('animals store module', () => {
let store
beforeEach(() => {
store = createStore({
modules: {
animals: animalsModule
}
})
})
it('should fetch animals list', async () => {
const mockAnimals = [
{ id: 1, breed: '安格斯牛' },
{ id: 2, breed: '西门塔尔牛' }
]
// Mock API response
jest.spyOn(api, 'getAnimals').mockResolvedValue(mockAnimals)
await store.dispatch('animals/fetchAnimals')
expect(store.state.animals.list).toEqual(mockAnimals)
expect(store.state.animals.loading).toBe(false)
})
})
```
### 3.2 后端单元测试
#### 3.2.1 API接口测试
```javascript
// tests/unit/controllers/animals.test.js
const request = require('supertest')
const app = require('../../../app')
const { Animal } = require('../../../models')
describe('Animals API', () => {
beforeEach(async () => {
await Animal.destroy({ where: {} })
})
describe('GET /api/animals', () => {
it('should return animals list', async () => {
// 创建测试数据
await Animal.create({
breed: '安格斯牛',
age: 12,
weight: 450,
status: 'healthy'
})
const response = await request(app)
.get('/api/animals')
.expect(200)
expect(response.body.success).toBe(true)
expect(response.body.data).toHaveLength(1)
expect(response.body.data[0].breed).toBe('安格斯牛')
})
})
describe('POST /api/animals', () => {
it('should create new animal', async () => {
const animalData = {
breed: '西门塔尔牛',
age: 10,
weight: 400,
status: 'healthy'
}
const response = await request(app)
.post('/api/animals')
.send(animalData)
.expect(201)
expect(response.body.success).toBe(true)
expect(response.body.data.breed).toBe('西门塔尔牛')
// 验证数据库中是否创建成功
const animal = await Animal.findByPk(response.body.data.id)
expect(animal).toBeTruthy()
expect(animal.breed).toBe('西门塔尔牛')
})
it('should validate required fields', async () => {
const response = await request(app)
.post('/api/animals')
.send({})
.expect(400)
expect(response.body.success).toBe(false)
expect(response.body.message).toContain('breed is required')
})
})
})
```
#### 3.2.2 业务逻辑测试
```javascript
// tests/unit/services/animalService.test.js
const AnimalService = require('../../../services/animalService')
const { Animal } = require('../../../models')
describe('AnimalService', () => {
describe('calculateAge', () => {
it('should calculate age correctly', () => {
const birthDate = new Date('2022-01-01')
const age = AnimalService.calculateAge(birthDate)
expect(age).toBeGreaterThan(0)
expect(typeof age).toBe('number')
})
})
describe('getHealthStatus', () => {
it('should return healthy status for normal weight', () => {
const animal = {
breed: '安格斯牛',
weight: 450,
age: 12
}
const status = AnimalService.getHealthStatus(animal)
expect(status).toBe('healthy')
})
it('should return underweight status for low weight', () => {
const animal = {
breed: '安格斯牛',
weight: 200,
age: 12
}
const status = AnimalService.getHealthStatus(animal)
expect(status).toBe('underweight')
})
})
})
```
### 3.3 小程序单元测试
```javascript
// miniprogram/tests/utils/formatDate.test.js
const { formatDate } = require('../../utils/formatDate')
describe('formatDate', () => {
it('should format date correctly', () => {
const date = new Date('2024-01-15T10:30:00')
const formatted = formatDate(date, 'YYYY-MM-DD')
expect(formatted).toBe('2024-01-15')
})
it('should handle invalid date', () => {
const formatted = formatDate(null, 'YYYY-MM-DD')
expect(formatted).toBe('')
})
})
```
## 4. 集成测试
### 4.1 API集成测试
```javascript
// tests/integration/api.test.js
const request = require('supertest')
const app = require('../../app')
describe('API Integration Tests', () => {
let authToken
beforeAll(async () => {
// 登录获取token
const loginResponse = await request(app)
.post('/api/auth/login')
.send({
username: 'test_admin',
password: 'test_password'
})
authToken = loginResponse.body.data.token
})
describe('Animals CRUD Operations', () => {
let animalId
it('should create animal', async () => {
const response = await request(app)
.post('/api/animals')
.set('Authorization', `Bearer ${authToken}`)
.send({
breed: '安格斯牛',
farmId: 1,
birthDate: '2023-01-15',
gender: 'male'
})
.expect(201)
animalId = response.body.data.id
expect(response.body.success).toBe(true)
})
it('should get animal details', async () => {
const response = await request(app)
.get(`/api/animals/${animalId}`)
.set('Authorization', `Bearer ${authToken}`)
.expect(200)
expect(response.body.data.breed).toBe('安格斯牛')
})
it('should update animal', async () => {
const response = await request(app)
.put(`/api/animals/${animalId}`)
.set('Authorization', `Bearer ${authToken}`)
.send({
weight: 450
})
.expect(200)
expect(response.body.data.weight).toBe(450)
})
it('should delete animal', async () => {
await request(app)
.delete(`/api/animals/${animalId}`)
.set('Authorization', `Bearer ${authToken}`)
.expect(200)
// 验证删除成功
await request(app)
.get(`/api/animals/${animalId}`)
.set('Authorization', `Bearer ${authToken}`)
.expect(404)
})
})
})
```
### 4.2 数据库集成测试
```javascript
// tests/integration/database.test.js
const { sequelize, User, Farm, Animal } = require('../../models')
describe('Database Integration Tests', () => {
beforeAll(async () => {
await sequelize.sync({ force: true })
})
afterAll(async () => {
await sequelize.close()
})
describe('Model Associations', () => {
it('should create user with farm and animals', async () => {
// 创建用户
const user = await User.create({
username: 'test_farmer',
email: 'farmer@test.com',
password: 'hashed_password',
role: 'farmer'
})
// 创建养殖场
const farm = await Farm.create({
name: '测试养殖场',
ownerId: user.id,
location: '北京市朝阳区',
area: 1000
})
// 创建动物
const animal = await Animal.create({
farmId: farm.id,
breed: '安格斯牛',
birthDate: new Date('2023-01-15'),
gender: 'male'
})
// 验证关联关系
const userWithFarms = await User.findByPk(user.id, {
include: [{
model: Farm,
include: [Animal]
}]
})
expect(userWithFarms.Farms).toHaveLength(1)
expect(userWithFarms.Farms[0].Animals).toHaveLength(1)
expect(userWithFarms.Farms[0].Animals[0].breed).toBe('安格斯牛')
})
})
})
```
## 5. 系统测试
### 5.1 功能测试用例
#### 5.1.1 用户管理功能测试
| 测试用例ID | 测试场景 | 测试步骤 | 预期结果 |
|------------|----------|----------|----------|
| TC_USER_001 | 用户注册 | 1. 访问注册页面
2. 填写用户信息
3. 点击注册按钮 | 注册成功,跳转到登录页面 |
| TC_USER_002 | 用户登录 | 1. 访问登录页面
2. 输入用户名密码
3. 点击登录按钮 | 登录成功,跳转到首页 |
| TC_USER_003 | 密码重置 | 1. 点击忘记密码
2. 输入邮箱
3. 查收邮件重置密码 | 密码重置成功 |
#### 5.1.2 养殖管理功能测试
| 测试用例ID | 测试场景 | 测试步骤 | 预期结果 |
|------------|----------|----------|----------|
| TC_FARM_001 | 添加养殖场 | 1. 进入养殖场管理
2. 点击添加养殖场
3. 填写养殖场信息
4. 保存 | 养殖场添加成功 |
| TC_ANIMAL_001 | 添加动物档案 | 1. 进入动物管理
2. 点击添加动物
3. 填写动物信息
4. 保存 | 动物档案创建成功 |
| TC_HEALTH_001 | 健康记录管理 | 1. 选择动物
2. 添加健康记录
3. 填写检查结果
4. 保存 | 健康记录保存成功 |
### 5.2 自动化测试脚本
#### 5.2.1 Selenium Web自动化测试
```python
# tests/e2e/test_user_login.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import unittest
class TestUserLogin(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.get("http://test.xlxumu.com")
def tearDown(self):
self.driver.quit()
def test_successful_login(self):
# 点击登录按钮
login_btn = self.driver.find_element(By.ID, "login-btn")
login_btn.click()
# 输入用户名
username_input = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.ID, "username"))
)
username_input.send_keys("test_admin")
# 输入密码
password_input = self.driver.find_element(By.ID, "password")
password_input.send_keys("test_password")
# 点击登录
submit_btn = self.driver.find_element(By.ID, "submit-btn")
submit_btn.click()
# 验证登录成功
WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "dashboard"))
)
self.assertIn("仪表板", self.driver.title)
def test_invalid_credentials(self):
# 输入错误的用户名密码
login_btn = self.driver.find_element(By.ID, "login-btn")
login_btn.click()
username_input = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.ID, "username"))
)
username_input.send_keys("invalid_user")
password_input = self.driver.find_element(By.ID, "password")
password_input.send_keys("invalid_password")
submit_btn = self.driver.find_element(By.ID, "submit-btn")
submit_btn.click()
# 验证错误提示
error_message = WebDriverWait(self.driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "error-message"))
)
self.assertIn("用户名或密码错误", error_message.text)
if __name__ == "__main__":
unittest.main()
```
#### 5.2.2 小程序自动化测试
```javascript
// tests/e2e/miniprogram/login.test.js
const automator = require('miniprogram-automator')
describe('小程序登录测试', () => {
let miniProgram
let page
beforeAll(async () => {
miniProgram = await automator.launch({
cliPath: '/Applications/wechatwebdevtools.app/Contents/MacOS/cli',
projectPath: './miniprogram'
})
page = await miniProgram.reLaunch('/pages/login/login')
})
afterAll(async () => {
await miniProgram.close()
})
it('should login successfully with valid credentials', async () => {
// 输入用户名
const usernameInput = await page.$('.username-input')
await usernameInput.input('test_user')
// 输入密码
const passwordInput = await page.$('.password-input')
await passwordInput.input('test_password')
// 点击登录按钮
const loginBtn = await page.$('.login-btn')
await loginBtn.tap()
// 等待跳转到首页
await page.waitFor(2000)
// 验证当前页面
const currentPath = await page.path
expect(currentPath).toBe('pages/index/index')
})
})
```
## 6. 性能测试
### 6.1 性能测试指标
| 指标类型 | 指标名称 | 目标值 | 测试方法 |
|----------|----------|--------|----------|
| 响应时间 | 页面加载时间 | < 3秒 | 浏览器性能测试 |
| 响应时间 | API响应时间 | < 500ms | 接口压力测试 |
| 吞吐量 | 并发用户数 | 1000+ | 负载测试 |
| 吞吐量 | 每秒请求数 | 500+ | 压力测试 |
| 资源使用 | CPU使用率 | < 70% | 系统监控 |
| 资源使用 | 内存使用率 | < 80% | 系统监控 |
### 6.2 JMeter性能测试脚本
```xml
总用例数: ${this.results.total}
通过: ${this.results.passed}
失败: ${this.results.failed}
跳过: ${this.results.skipped}
通过率: ${((this.results.passed / this.results.total) * 100).toFixed(2)}%
| 测试套件 | 测试用例 | 状态 | 执行时间 | 错误信息 |
|---|---|---|---|---|
| ${suite.name} | ${test.name} | ${test.status} | ${test.duration}ms | ${test.error || ''} |
报告生成时间: ${new Date().toLocaleString()}
` return template } saveReport(filename = 'test-report.html') { const html = this.generateHTML() fs.writeFileSync(filename, html) console.log(`测试报告已生成: ${filename}`) } } module.exports = TestReporter ``` ## 9. 测试工具和环境 ### 9.1 测试工具清单 | 工具类型 | 工具名称 | 版本 | 用途 | |----------|----------|------|------| | 单元测试 | Jest | 29.x | JavaScript单元测试 | | 单元测试 | Vue Test Utils | 2.x | Vue组件测试 | | 集成测试 | Supertest | 6.x | API集成测试 | | E2E测试 | Selenium | 4.x | Web自动化测试 | | E2E测试 | Miniprogram Automator | 0.x | 小程序自动化测试 | | 性能测试 | JMeter | 5.x | 性能压力测试 | | 安全测试 | OWASP ZAP | 2.x | 安全漏洞扫描 | | 测试管理 | TestRail | - | 测试用例管理 | ### 9.2 CI/CD集成 ```yaml # .github/workflows/test.yml name: 自动化测试 on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest services: mysql: image: mysql:8.0 env: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: test_db options: >- --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 redis: image: redis:6-alpine options: >- --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Run unit tests run: npm run test:unit - name: Run integration tests run: npm run test:integration env: DATABASE_URL: mysql://root:root@localhost:3306/test_db REDIS_URL: redis://localhost:6379 - name: Run E2E tests run: npm run test:e2e - name: Generate test report run: npm run test:report - name: Upload test results uses: actions/upload-artifact@v3 with: name: test-results path: test-results/ ``` ## 10. 总结 ### 10.1 测试策略总结 本测试文档建立了完整的测试体系,包括: 1. **多层次测试**:从单元测试到系统测试的完整覆盖 2. **自动化测试**:提高测试效率和准确性 3. **性能测试**:确保系统性能满足要求 4. **安全测试**:保障系统安全可靠 5. **持续集成**:自动化测试流程 ### 10.2 测试质量保证 - **测试覆盖率**:代码覆盖率 > 80% - **自动化率**:自动化测试覆盖率 > 70% - **缺陷密度**:< 2个缺陷/KLOC - **测试效率**:回归测试时间 < 2小时 ### 10.3 持续改进 1. **测试工具升级**:定期更新测试工具和框架 2. **测试流程优化**:持续优化测试流程和方法 3. **团队技能提升**:加强测试团队技能培训 4. **质量度量**:建立完善的质量度量体系 --- **文档版本**: v1.0.0 **最后更新**: 2024年12月 **维护团队**: 测试团队