30 KiB
30 KiB
测试文档
版本历史
| 版本 | 日期 | 作者 | 变更说明 |
|---|---|---|---|
| 1.0 | 2024-01-20 | 测试团队 | 初始版本 |
| 1.1 | 2024-09-21 | 测试团队 | 更新测试策略,与实际项目保持一致 |
1. 测试概述
1.1 测试目标
确保畜牧养殖管理平台的功能完整性、性能稳定性、安全可靠性,为用户提供高质量的软件产品。
1.2 测试范围
- 功能测试:验证系统功能是否符合需求规格说明
- 性能测试:验证系统在各种负载下的性能表现
- 安全测试:验证系统的安全防护能力
- 兼容性测试:验证系统在不同环境下的兼容性
- 用户体验测试:验证系统的易用性和用户体验
1.3 测试策略
采用分层测试策略,包括单元测试、集成测试、系统测试和验收测试。
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 测试数据准备
-- 测试数据初始化脚本
-- 用户测试数据
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组件测试
// 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测试
// 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接口测试
// 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 业务逻辑测试
// 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 小程序单元测试
// 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集成测试
// 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 数据库集成测试
// 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自动化测试
# 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 小程序自动化测试
// 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性能测试脚本
<!-- performance-test.jmx -->
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="畜牧管理平台性能测试">
<elementProp name="TestPlan.arguments" elementType="Arguments" guiclass="ArgumentsPanel">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
</TestPlan>
<hashTree>
<!-- 线程组配置 -->
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="用户登录压力测试">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">10</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">100</stringProp>
<stringProp name="ThreadGroup.ramp_time">60</stringProp>
</ThreadGroup>
<hashTree>
<!-- HTTP请求配置 -->
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="登录请求">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="HTTPArgument">
<boolProp name="HTTPArgument.always_encode">false</boolProp>
<stringProp name="Argument.value">{"username":"test_user","password":"test_password"}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="HTTPSampler.domain">test.xlxumu.com</stringProp>
<stringProp name="HTTPSampler.port">80</stringProp>
<stringProp name="HTTPSampler.protocol">http</stringProp>
<stringProp name="HTTPSampler.path">/api/auth/login</stringProp>
<stringProp name="HTTPSampler.method">POST</stringProp>
</HTTPSamplerProxy>
<!-- 响应断言 -->
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="响应断言">
<collectionProp name="Asserion.test_strings">
<stringProp name="success">true</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">2</intProp>
</ResponseAssertion>
</hashTree>
</hashTree>
</hashTree>
</jmeterTestPlan>
6.3 性能监控脚本
#!/bin/bash
# performance-monitor.sh
# 性能监控脚本
echo "开始性能监控..."
# 监控CPU使用率
echo "CPU使用率:"
top -l 1 | grep "CPU usage"
# 监控内存使用率
echo "内存使用率:"
vm_stat | grep "Pages free\|Pages active\|Pages inactive\|Pages speculative\|Pages wired down"
# 监控磁盘使用率
echo "磁盘使用率:"
df -h
# 监控网络连接
echo "网络连接数:"
netstat -an | grep ESTABLISHED | wc -l
# 监控数据库连接
echo "数据库连接数:"
mysql -u root -p -e "SHOW STATUS LIKE 'Threads_connected';"
# 监控Redis连接
echo "Redis连接数:"
redis-cli info clients | grep connected_clients
7. 安全测试
7.1 安全测试检查项
| 安全类型 | 检查项 | 测试方法 | 风险等级 |
|---|---|---|---|
| 身份认证 | 弱密码检测 | 密码策略测试 | 高 |
| 身份认证 | 会话管理 | 会话超时测试 | 中 |
| 授权控制 | 权限绕过 | 越权访问测试 | 高 |
| 数据验证 | SQL注入 | 注入攻击测试 | 高 |
| 数据验证 | XSS攻击 | 脚本注入测试 | 中 |
| 数据传输 | HTTPS加密 | 传输加密测试 | 高 |
| 数据存储 | 敏感数据加密 | 数据加密测试 | 高 |
7.2 安全测试工具
7.2.1 OWASP ZAP自动化扫描
# security_scan.py
from zapv2 import ZAPv2
import time
# ZAP代理配置
zap = ZAPv2(proxies={'http': 'http://127.0.0.1:8080', 'https': 'http://127.0.0.1:8080'})
# 目标URL
target = 'http://test.xlxumu.com'
# 开始爬虫扫描
print('开始爬虫扫描...')
scanid = zap.spider.scan(target)
time.sleep(2)
while int(zap.spider.status(scanid)) < 100:
print(f'爬虫进度: {zap.spider.status(scanid)}%')
time.sleep(2)
print('爬虫扫描完成')
# 开始主动扫描
print('开始主动安全扫描...')
scanid = zap.ascan.scan(target)
while int(zap.ascan.status(scanid)) < 100:
print(f'扫描进度: {zap.ascan.status(scanid)}%')
time.sleep(5)
print('安全扫描完成')
# 生成报告
print('生成安全报告...')
with open('security_report.html', 'w') as f:
f.write(zap.core.htmlreport())
print('安全报告已生成: security_report.html')
7.2.2 SQL注入测试
# sql_injection_test.py
import requests
import json
def test_sql_injection():
"""SQL注入测试"""
base_url = "http://test.xlxumu.com/api"
# 测试用例
injection_payloads = [
"' OR '1'='1",
"'; DROP TABLE users; --",
"' UNION SELECT * FROM users --",
"1' AND (SELECT COUNT(*) FROM users) > 0 --"
]
# 测试登录接口
for payload in injection_payloads:
data = {
"username": payload,
"password": "test"
}
response = requests.post(f"{base_url}/auth/login", json=data)
if response.status_code == 200:
result = response.json()
if result.get('success'):
print(f"⚠️ 可能存在SQL注入漏洞: {payload}")
else:
print(f"✅ 防护正常: {payload}")
else:
print(f"✅ 请求被拒绝: {payload}")
if __name__ == "__main__":
test_sql_injection()
8. 测试报告
8.1 测试执行报告模板
# 测试执行报告
## 基本信息
- **项目名称**: 畜牧养殖管理平台
- **测试版本**: v1.0.0
- **测试环境**: 测试环境
- **测试时间**: 2024-01-20 ~ 2024-01-25
- **测试负责人**: 张三
## 测试概况
- **计划测试用例**: 150个
- **实际执行用例**: 148个
- **通过用例**: 142个
- **失败用例**: 6个
- **阻塞用例**: 2个
- **测试通过率**: 95.9%
## 功能测试结果
| 功能模块 | 计划用例 | 执行用例 | 通过用例 | 失败用例 | 通过率 |
|----------|----------|----------|----------|----------|--------|
| 用户管理 | 25 | 25 | 24 | 1 | 96% |
| 养殖管理 | 40 | 40 | 38 | 2 | 95% |
| 交易管理 | 30 | 30 | 29 | 1 | 97% |
| 财务管理 | 20 | 20 | 19 | 1 | 95% |
| 系统管理 | 15 | 15 | 15 | 0 | 100% |
| 数据统计 | 20 | 18 | 17 | 1 | 94% |
## 性能测试结果
| 测试指标 | 目标值 | 实际值 | 是否达标 |
|----------|--------|--------|----------|
| 页面加载时间 | < 3秒 | 2.1秒 | ✅ |
| API响应时间 | < 500ms | 320ms | ✅ |
| 并发用户数 | 1000+ | 1200 | ✅ |
| CPU使用率 | < 70% | 65% | ✅ |
| 内存使用率 | < 80% | 72% | ✅ |
## 安全测试结果
| 安全项目 | 测试结果 | 风险等级 | 处理状态 |
|----------|----------|----------|----------|
| SQL注入 | 无漏洞 | 无 | ✅ |
| XSS攻击 | 发现1个 | 中 | 🔄 修复中 |
| 权限控制 | 无问题 | 无 | ✅ |
| 数据加密 | 符合要求 | 无 | ✅ |
## 缺陷统计
| 缺陷等级 | 数量 | 已修复 | 待修复 |
|----------|------|--------|--------|
| 严重 | 2 | 1 | 1 |
| 一般 | 4 | 3 | 1 |
| 轻微 | 8 | 6 | 2 |
| 建议 | 5 | 2 | 3 |
## 测试结论
系统整体功能完整,性能表现良好,安全防护到位。建议修复剩余缺陷后发布。
8.2 自动化测试报告生成
// generate-test-report.js
const fs = require('fs')
const path = require('path')
class TestReporter {
constructor() {
this.results = {
total: 0,
passed: 0,
failed: 0,
skipped: 0,
suites: []
}
}
addSuite(suite) {
this.results.suites.push(suite)
this.results.total += suite.tests.length
this.results.passed += suite.tests.filter(t => t.status === 'passed').length
this.results.failed += suite.tests.filter(t => t.status === 'failed').length
this.results.skipped += suite.tests.filter(t => t.status === 'skipped').length
}
generateHTML() {
const template = `
<!DOCTYPE html>
<html>
<head>
<title>测试报告</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.summary { background: #f5f5f5; padding: 15px; border-radius: 5px; }
.passed { color: green; }
.failed { color: red; }
.skipped { color: orange; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>测试执行报告</h1>
<div class="summary">
<h2>测试概况</h2>
<p>总用例数: ${this.results.total}</p>
<p class="passed">通过: ${this.results.passed}</p>
<p class="failed">失败: ${this.results.failed}</p>
<p class="skipped">跳过: ${this.results.skipped}</p>
<p>通过率: ${((this.results.passed / this.results.total) * 100).toFixed(2)}%</p>
</div>
<h2>详细结果</h2>
<table>
<thead>
<tr>
<th>测试套件</th>
<th>测试用例</th>
<th>状态</th>
<th>执行时间</th>
<th>错误信息</th>
</tr>
</thead>
<tbody>
${this.results.suites.map(suite =>
suite.tests.map(test => `
<tr>
<td>${suite.name}</td>
<td>${test.name}</td>
<td class="${test.status}">${test.status}</td>
<td>${test.duration}ms</td>
<td>${test.error || ''}</td>
</tr>
`).join('')
).join('')}
</tbody>
</table>
<p>报告生成时间: ${new Date().toLocaleString()}</p>
</body>
</html>
`
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集成
# .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 测试策略总结
本测试文档建立了完整的测试体系,包括:
- 多层次测试:从单元测试到系统测试的完整覆盖
- 自动化测试:提高测试效率和准确性
- 性能测试:确保系统性能满足要求
- 安全测试:保障系统安全可靠
- 持续集成:自动化测试流程
10.2 测试质量保证
- 测试覆盖率:代码覆盖率 > 80%
- 自动化率:自动化测试覆盖率 > 70%
- 缺陷密度:< 2个缺陷/KLOC
- 测试效率:回归测试时间 < 2小时
10.3 持续改进
- 测试工具升级:定期更新测试工具和框架
- 测试流程优化:持续优化测试流程和方法
- 团队技能提升:加强测试团队技能培训
- 质量度量:建立完善的质量度量体系
文档版本: v1.0.0
最后更新: 2024年12月
维护团队: 测试团队