This commit is contained in:
hailin 2025-11-24 03:21:24 -08:00
parent fbcef7aba2
commit 4cdd0b07b9
8 changed files with 1063 additions and 0 deletions

View File

@ -0,0 +1,238 @@
# Identity Service 测试策略
## 测试金字塔
```
/\
/ \ E2E Tests (20)
/----\
/ \ Integration Tests
/--------\
/ \ Unit Tests (46)
/--------------\
```
## 当前测试状态
### ✅ 已完成
- **单元测试**: 46 个测试全部通过
- 领域层值对象测试
- 领域层聚合根测试
- 基础设施层服务测试
- **E2E 测试**: 20 个测试全部通过
- 账户创建流程
- 用户资料管理
- 设备管理
- Token 管理
- 推荐系统
- KYC 认证
- 助记词恢复
- 数据验证
### ⚠️ 需要补充的测试
#### 1. 集成测试(优先级:高)
- [ ] PostgreSQL 真实连接测试
- [ ] Redis 真实连接测试
- [ ] Kafka 真实连接测试
- [ ] 事务一致性测试
- [ ] 并发安全测试
#### 2. 性能测试(优先级:高)
- [ ] 负载测试100-500 并发)
- [ ] 压力测试(找到系统极限)
- [ ] 数据库连接池测试
- [ ] 内存泄漏测试
#### 3. 安全测试(优先级:高)
- [ ] SQL 注入测试
- [ ] XSS 攻击测试
- [ ] JWT Token 安全测试
- [ ] 暴力破解防护测试
- [ ] 敏感数据保护验证
- [ ] 依赖漏洞扫描npm audit, Snyk
#### 4. 手动测试(优先级:中)
- [ ] 完整用户旅程测试
- [ ] 多设备管理流程测试
- [ ] 边界条件测试
- [ ] 异常场景测试
#### 5. 代码质量检查(优先级:中)
- [ ] 测试覆盖率分析(目标 >80%
- [ ] 代码规范检查ESLint
- [ ] 类型安全检查TypeScript
- [ ] 代码复杂度分析
- [ ] 依赖关系分析
## 测试执行指南
### 开发阶段
```bash
# 1. 运行单元测试(每次代码修改后)
npm test
# 2. 运行 E2E 测试(每次功能完成后)
npm run test:e2e
# 3. 生成覆盖率报告
npm run test:cov
# 4. 代码规范检查
npm run lint
```
### 提交前检查
```bash
# 运行完整测试套件
npm run test:all # 需要在 package.json 中添加这个脚本
# 格式化代码
npm run format
# 类型检查
npm run build
```
### 部署前检查
```bash
# 1. 健康检查
./scripts/health-check.sh
# 2. 快速功能测试
./scripts/quick-test.sh
# 3. 安全扫描
npm audit
snyk test
# 4. 性能测试(如果有)
k6 run performance-test.js
```
## 测试环境配置
### 本地开发环境
```bash
# .env.test
NODE_ENV=test
DATABASE_URL=postgresql://test:test@localhost:5432/identity_test
REDIS_URL=redis://localhost:6379
KAFKA_BROKERS=localhost:9092
JWT_SECRET=test-secret-key-for-testing-only
```
### CI/CD 环境
- GitHub Actions / GitLab CI
- 每次 push 自动运行单元测试
- 每次 merge 到 main 自动运行 E2E 测试
- 每日定时运行安全扫描
### 测试环境Staging
- 与生产环境配置相同
- 使用真实的外部服务(测试账号)
- 运行完整的集成测试和性能测试
## 测试数据管理
### 测试数据策略
1. **单元测试**: 使用 mock 数据,测试快速、隔离
2. **E2E 测试**: 使用测试数据库,每次测试前清理
3. **集成测试**: 使用真实服务,测试账号/测试环境
4. **性能测试**: 使用大量模拟数据
### 测试数据库种子数据
```bash
# 初始化测试数据
npm run seed:test
# 清理测试数据
npm run seed:reset
```
## 持续改进
### 每个 Sprint
- [ ] 为新功能编写测试TDD
- [ ] 修复失败的测试
- [ ] 提高测试覆盖率(+5%
- [ ] 更新测试文档
### 每个月
- [ ] 运行完整的性能测试
- [ ] 运行安全扫描
- [ ] 更新依赖版本
- [ ] 代码质量回顾
### 每个季度
- [ ] 渗透测试
- [ ] 灾难恢复演练
- [ ] 测试策略回顾和优化
## 测试指标
### 代码覆盖率目标
- 整体覆盖率: **>80%**
- 领域层: **>95%**
- 应用层: **>90%**
- 基础设施层: **>80%**
- API 层: **>85%**
### 性能指标目标
- API 响应时间 P95: **<500ms**
- 数据库查询时间: **<100ms**
- 并发处理能力: **>500 TPS**
- 错误率: **<0.1%**
### 质量指标目标
- 代码复杂度: **<10**
- 代码重复率: **<5%**
- 技术债务比率: **<5%**
- 安全漏洞: **0 个高危**
## 测试清单快速链接
- [集成测试清单](./test/integration-checklist.md)
- [性能测试计划](./test/performance-test.md)
- [安全测试清单](./test/security-test-checklist.md)
- [手动测试场景](./test/manual-test-scenarios.md)
- [代码质量清单](./test/code-quality-checklist.md)
## 常见问题
### Q: 测试失败怎么办?
1. 查看错误日志
2. 在本地复现问题
3. 调试并修复
4. 确认测试通过后提交
### Q: 如何提高测试覆盖率?
1. 使用 `npm run test:cov` 查看未覆盖的代码
2. 为未覆盖的分支添加测试用例
3. 重点关注领域逻辑和边界条件
### Q: 测试运行太慢怎么办?
1. 只运行相关测试: `npm test -- user-account.spec.ts`
2. 使用 mock 替代真实服务
3. 并行运行测试Jest 默认并行)
4. 优化测试数据准备逻辑
## 结论
当前测试覆盖已经包括:
- ✅ 核心业务逻辑(单元测试)
- ✅ API 端到端流程E2E 测试)
- ✅ Mock 外部依赖
**但要真正适应生产环境,还需要:**
1. **集成测试** - 验证与真实服务的交互
2. **性能测试** - 验证系统在高负载下的表现
3. **安全测试** - 发现潜在的安全漏洞
4. **手动测试** - 验证用户体验和边界情况
**推荐的测试优先级:**
1. 🔴 **立即进行**: 集成测试PostgreSQL/Redis/Kafka
2. 🟡 **本周完成**: 安全测试基础(依赖扫描、输入验证)
3. 🟢 **下周完成**: 性能测试、手动测试
4. 🔵 **持续进行**: 代码质量检查、覆盖率提升

View File

@ -0,0 +1,67 @@
#!/bin/bash
# 健康检查脚本 - 检查所有依赖服务是否正常
set -e
echo "🏥 开始健康检查..."
echo ""
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
# 检查计数
PASS=0
FAIL=0
# 检查函数
check_service() {
local service_name=$1
local check_command=$2
echo -n "Checking $service_name ... "
if eval "$check_command" > /dev/null 2>&1; then
echo -e "${GREEN}✓ OK${NC}"
PASS=$((PASS + 1))
else
echo -e "${RED}✗ FAIL${NC}"
FAIL=$((FAIL + 1))
fi
}
# 检查 PostgreSQL
echo -e "${YELLOW}=== 数据库服务 ===${NC}"
check_service "PostgreSQL" "pg_isready -h localhost -p 5432"
# 检查 Redis
echo -e "${YELLOW}=== 缓存服务 ===${NC}"
check_service "Redis" "redis-cli -h localhost -p 6379 ping"
# 检查 Kafka
echo -e "${YELLOW}=== 消息队列服务 ===${NC}"
check_service "Kafka" "nc -zv localhost 9092"
# 检查应用服务
echo -e "${YELLOW}=== 应用服务 ===${NC}"
check_service "Identity Service" "curl -f http://localhost:3000/health"
# 检查 Swagger 文档
echo -e "${YELLOW}=== API 文档 ===${NC}"
check_service "Swagger UI" "curl -f http://localhost:3000/api"
echo ""
echo -e "${YELLOW}======================================${NC}"
echo -e "${YELLOW}健康检查完成!${NC}"
echo -e "${GREEN}正常: $PASS${NC}"
echo -e "${RED}异常: $FAIL${NC}"
echo -e "${YELLOW}======================================${NC}"
if [ $FAIL -eq 0 ]; then
echo -e "${GREEN}✓ 所有服务正常!${NC}"
exit 0
else
echo -e "${RED}✗ 存在异常的服务!${NC}"
exit 1
fi

View File

@ -0,0 +1,179 @@
#!/bin/bash
# 快速测试脚本 - 在本地环境快速验证核心功能
set -e
echo "🚀 开始快速测试..."
echo ""
# 颜色定义
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
BASE_URL="http://localhost:3000/api/v1"
# 测试结果统计
PASS=0
FAIL=0
# 测试函数
test_api() {
local test_name=$1
local method=$2
local endpoint=$3
local data=$4
local expected_status=$5
local token=$6
echo -n "Testing: $test_name ... "
if [ -n "$token" ]; then
response=$(curl -s -w "\n%{http_code}" -X $method "$BASE_URL$endpoint" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $token" \
-d "$data")
else
response=$(curl -s -w "\n%{http_code}" -X $method "$BASE_URL$endpoint" \
-H "Content-Type: application/json" \
-d "$data")
fi
status=$(echo "$response" | tail -n1)
body=$(echo "$response" | head -n-1)
if [ "$status" -eq "$expected_status" ]; then
echo -e "${GREEN}✓ PASS${NC}"
PASS=$((PASS + 1))
echo "$body"
else
echo -e "${RED}✗ FAIL${NC} (Expected: $expected_status, Got: $status)"
FAIL=$((FAIL + 1))
echo "$body"
fi
echo ""
}
# 生成随机设备 ID
DEVICE_ID="test-device-$(date +%s)"
# 1. 测试账户创建
echo -e "${YELLOW}=== 1. 账户创建 ===${NC}"
CREATE_RESPONSE=$(curl -s -X POST "$BASE_URL/user/auto-create" \
-H "Content-Type: application/json" \
-d "{
\"deviceId\": \"$DEVICE_ID\",
\"deviceName\": \"Test Device\",
\"provinceCode\": \"110000\",
\"cityCode\": \"110100\"
}")
echo "$CREATE_RESPONSE" | jq '.'
# 提取关键信息
ACCESS_TOKEN=$(echo "$CREATE_RESPONSE" | jq -r '.data.accessToken')
REFRESH_TOKEN=$(echo "$CREATE_RESPONSE" | jq -r '.data.refreshToken')
ACCOUNT_SEQUENCE=$(echo "$CREATE_RESPONSE" | jq -r '.data.accountSequence')
MNEMONIC=$(echo "$CREATE_RESPONSE" | jq -r '.data.mnemonic')
REFERRAL_CODE=$(echo "$CREATE_RESPONSE" | jq -r '.data.referralCode')
if [ "$ACCESS_TOKEN" != "null" ]; then
echo -e "${GREEN}✓ 账户创建成功${NC}"
echo "Account Sequence: $ACCOUNT_SEQUENCE"
echo "Referral Code: $REFERRAL_CODE"
PASS=$((PASS + 1))
else
echo -e "${RED}✗ 账户创建失败${NC}"
FAIL=$((FAIL + 1))
exit 1
fi
echo ""
# 2. 测试获取个人资料
echo -e "${YELLOW}=== 2. 获取个人资料 ===${NC}"
test_api "获取个人资料" "GET" "/user/my-profile" "" 200 "$ACCESS_TOKEN"
# 3. 测试更新个人资料
echo -e "${YELLOW}=== 3. 更新个人资料 ===${NC}"
test_api "更新个人资料" "PUT" "/user/update-profile" \
"{\"nickname\": \"测试用户\", \"address\": \"测试地址\"}" \
200 "$ACCESS_TOKEN"
# 4. 测试获取设备列表
echo -e "${YELLOW}=== 4. 获取设备列表 ===${NC}"
test_api "获取设备列表" "GET" "/user/my-devices" "" 200 "$ACCESS_TOKEN"
# 5. 测试 Token 刷新
echo -e "${YELLOW}=== 5. Token 刷新 ===${NC}"
REFRESH_RESPONSE=$(curl -s -X POST "$BASE_URL/user/auto-login" \
-H "Content-Type: application/json" \
-d "{
\"refreshToken\": \"$REFRESH_TOKEN\",
\"deviceId\": \"$DEVICE_ID\"
}")
NEW_ACCESS_TOKEN=$(echo "$REFRESH_RESPONSE" | jq -r '.data.accessToken')
if [ "$NEW_ACCESS_TOKEN" != "null" ] && [ "$NEW_ACCESS_TOKEN" != "$ACCESS_TOKEN" ]; then
echo -e "${GREEN}✓ Token 刷新成功${NC}"
PASS=$((PASS + 1))
else
echo -e "${RED}✗ Token 刷新失败${NC}"
FAIL=$((FAIL + 1))
fi
echo ""
# 6. 测试助记词恢复
echo -e "${YELLOW}=== 6. 助记词恢复 ===${NC}"
NEW_DEVICE_ID="test-device-recovery-$(date +%s)"
test_api "助记词恢复" "POST" "/user/recover-by-mnemonic" \
"{
\"accountSequence\": $ACCOUNT_SEQUENCE,
\"mnemonic\": \"$MNEMONIC\",
\"newDeviceId\": \"$NEW_DEVICE_ID\",
\"deviceName\": \"Recovered Device\"
}" \
201 ""
# 7. 测试推荐码查询
echo -e "${YELLOW}=== 7. 推荐码查询 ===${NC}"
test_api "推荐码查询" "GET" "/user/by-referral-code/$REFERRAL_CODE" "" 200 ""
# 8. 测试 KYC 提交
echo -e "${YELLOW}=== 8. KYC 提交 ===${NC}"
test_api "KYC 提交" "POST" "/user/submit-kyc" \
"{
\"realName\": \"张三\",
\"idCardNumber\": \"110101199001011234\",
\"idCardFrontUrl\": \"https://example.com/front.jpg\",
\"idCardBackUrl\": \"https://example.com/back.jpg\"
}" \
201 "$ACCESS_TOKEN"
# 9. 测试错误场景
echo -e "${YELLOW}=== 9. 错误场景测试 ===${NC}"
test_api "无效 Token" "GET" "/user/my-profile" "" 401 "invalid-token"
test_api "错误的助记词" "POST" "/user/recover-by-mnemonic" \
"{
\"accountSequence\": $ACCOUNT_SEQUENCE,
\"mnemonic\": \"wrong wrong wrong wrong wrong wrong wrong wrong wrong wrong wrong wrong\",
\"newDeviceId\": \"wrong-device\",
\"deviceName\": \"Wrong Device\"
}" \
400 ""
# 总结
echo ""
echo -e "${YELLOW}======================================${NC}"
echo -e "${YELLOW}测试完成!${NC}"
echo -e "${GREEN}通过: $PASS${NC}"
echo -e "${RED}失败: $FAIL${NC}"
echo -e "${YELLOW}======================================${NC}"
if [ $FAIL -eq 0 ]; then
echo -e "${GREEN}✓ 所有测试通过!${NC}"
exit 0
else
echo -e "${RED}✗ 存在失败的测试!${NC}"
exit 1
fi

View File

@ -0,0 +1,169 @@
# 代码质量检查清单
## 自动化工具
### 1. ESLint - 代码规范检查
```bash
npm run lint
```
### 2. Prettier - 代码格式化
```bash
npm run format
npm run format:check
```
### 3. TypeScript 类型检查
```bash
npm run build
# 或
tsc --noEmit
```
### 4. 测试覆盖率
```bash
npm run test:cov
```
**目标覆盖率:**
- 整体覆盖率 > 80%
- 关键业务逻辑 > 90%
- 领域模型 > 95%
### 5. SonarQube - 代码质量分析
```bash
# Docker 启动 SonarQube
docker run -d --name sonarqube -p 9000:9000 sonarqube:latest
# 扫描项目
npx sonar-scanner \
-Dsonar.projectKey=identity-service \
-Dsonar.sources=src \
-Dsonar.host.url=http://localhost:9000
```
检查指标:
- Code Smells
- Bugs
- Vulnerabilities
- Security Hotspots
- Duplications
- Technical Debt
### 6. 循环复杂度检查
```bash
npm install -g complexity-report
cr --format json src/**/*.ts
```
**目标:**
- 函数循环复杂度 < 10
- 文件平均复杂度 < 5
## 手动代码审查清单
### 架构和设计
- [ ] 遵循 DDD 原则
- [ ] 清晰的层次划分Domain/Application/Infrastructure/API
- [ ] 依赖方向正确(外层依赖内层,内层不依赖外层)
- [ ] 没有循环依赖
- [ ] 接口隔离,依赖倒置
### 领域层
- [ ] 值对象是不可变的
- [ ] 实体有唯一标识
- [ ] 聚合根控制一致性边界
- [ ] 领域事件正确发布
- [ ] 业务规则在领域层,不在应用层
### 应用层
- [ ] Command/Query 职责明确
- [ ] Handler 只协调,不包含业务逻辑
- [ ] 事务边界合理
- [ ] 异常处理恰当
### 基础设施层
- [ ] Repository 不泄露持久化细节
- [ ] 外部服务接口清晰
- [ ] 错误处理和重试机制
### API 层
- [ ] DTO 验证充分
- [ ] 错误响应统一
- [ ] API 文档完整Swagger
- [ ] 版本控制策略
### 安全
- [ ] 没有硬编码的密钥/密码
- [ ] 敏感数据加密
- [ ] 输入验证和消毒
- [ ] SQL 注入防护(使用 ORM
- [ ] XSS 防护
### 性能
- [ ] 没有 N+1 查询
- [ ] 合理使用索引
- [ ] 避免阻塞操作
- [ ] 合理的缓存策略
- [ ] 分页查询,避免全表扫描
### 可维护性
- [ ] 代码可读性好
- [ ] 函数/类职责单一
- [ ] 命名清晰准确
- [ ] 注释充分但不冗余
- [ ] 避免魔法数字
### 测试
- [ ] 单元测试覆盖关键逻辑
- [ ] 测试用例清晰可读
- [ ] 测试独立,不依赖顺序
- [ ] Mock 使用恰当
## 依赖分析
### 检查依赖关系
```bash
npm install -g madge
# 生成依赖图
madge --image deps.png src/
# 检查循环依赖
madge --circular src/
```
### 检查未使用的依赖
```bash
npm install -g depcheck
depcheck
```
### 检查过时的依赖
```bash
npm outdated
```
## 文档检查
- [ ] README.md 完整
- [ ] 项目介绍
- [ ] 安装步骤
- [ ] 运行命令
- [ ] 环境变量说明
- [ ] API 文档链接
- [ ] 架构文档
- [ ] 系统架构图
- [ ] 领域模型图
- [ ] 数据库 ER 图
- [ ] API 接口文档
- [ ] 开发文档
- [ ] 开发环境搭建
- [ ] 编码规范
- [ ] Git 工作流
- [ ] 测试指南
## Git 提交质量
- [ ] Commit message 清晰
- [ ] 每个 commit 是原子性的
- [ ] 没有提交敏感信息
- [ ] 分支策略清晰

View File

@ -0,0 +1,40 @@
# 集成测试检查清单
## 数据库集成测试
- [ ] PostgreSQL 真实连接测试
- [ ] 事务回滚测试
- [ ] 并发写入测试(多个账户同时创建)
- [ ] 账户序列号生成器的并发安全性
- [ ] 外键约束测试
- [ ] 索引性能测试
## Redis 集成测试
- [ ] Redis 真实连接测试
- [ ] Token 存储/读取/过期
- [ ] SMS 验证码存储/过期
- [ ] 分布式锁测试(防止重复注册)
## Kafka 集成测试
- [ ] Kafka 真实连接测试
- [ ] 事件发布成功
- [ ] 事件发布失败重试
- [ ] 事件顺序保证
- [ ] 消费者能正确接收事件
## SMS 服务集成测试
- [ ] 真实 SMS API 调用(使用测试号码)
- [ ] 发送成功
- [ ] 发送失败处理
- [ ] 限流测试(防止恶意发送)
## JWT Token 测试
- [ ] Token 签名验证
- [ ] Token 过期验证
- [ ] Token 刷新流程
- [ ] 跨服务 Token 验证(如果有多个服务)
## 区块链钱包测试
- [ ] 助记词生成的随机性
- [ ] 地址派生的一致性
- [ ] 加密/解密的安全性
- [ ] 多链地址格式验证

View File

@ -0,0 +1,176 @@
# 手动测试场景
## 用户旅程测试
### 场景 1: 新用户完整注册流程
1. **自动创建账户**
```bash
curl -X POST http://localhost:3000/api/v1/user/auto-create \
-H "Content-Type: application/json" \
-d '{
"deviceId": "manual-test-device-001",
"deviceName": "iPhone 14 Pro",
"provinceCode": "110000",
"cityCode": "110100"
}'
```
- ✅ 返回 201
- ✅ 获得 userId, accountSequence, referralCode, mnemonic
- ✅ 获得 3 个钱包地址 (KAVA, DST, BSC)
- ✅ 获得 accessToken 和 refreshToken
- **保存 mnemonic 用于后续测试!**
2. **查看个人资料**
```bash
curl -X GET http://localhost:3000/api/v1/user/my-profile \
-H "Authorization: Bearer {accessToken}"
```
- ✅ 返回正确的用户信息
3. **更新个人资料**
```bash
curl -X PUT http://localhost:3000/api/v1/user/update-profile \
-H "Authorization: Bearer {accessToken}" \
-H "Content-Type: application/json" \
-d '{
"nickname": "测试用户",
"avatarUrl": "https://example.com/avatar.jpg",
"address": "北京市朝阳区测试路123号"
}'
```
- ✅ 更新成功
- ✅ 再次查询个人资料,确认更新生效
4. **查看设备列表**
```bash
curl -X GET http://localhost:3000/api/v1/user/my-devices \
-H "Authorization: Bearer {accessToken}"
```
- ✅ 看到 1 个设备
### 场景 2: 多设备管理
5. **在新设备上使用助记词恢复**
```bash
curl -X POST http://localhost:3000/api/v1/user/recover-by-mnemonic \
-H "Content-Type: application/json" \
-d '{
"accountSequence": {accountSequence},
"mnemonic": "{mnemonic}",
"newDeviceId": "manual-test-device-002",
"deviceName": "iPad Pro"
}'
```
- ✅ 返回新的 token
- ✅ 钱包地址与第一个设备相同
6. **查看设备列表(使用新设备的 token**
- ✅ 看到 2 个设备
7. **移除旧设备**
```bash
curl -X POST http://localhost:3000/api/v1/user/remove-device \
-H "Authorization: Bearer {newAccessToken}" \
-H "Content-Type: application/json" \
-d '{
"deviceId": "manual-test-device-001"
}'
```
- ✅ 移除成功
- ✅ 使用旧设备的 token 无法再访问 API
### 场景 3: Token 管理
8. **等待 access token 过期(或修改过期时间为 1 分钟测试)**
- ✅ 过期的 token 无法访问 API
9. **使用 refresh token 获取新的 access token**
```bash
curl -X POST http://localhost:3000/api/v1/user/auto-login \
-H "Content-Type: application/json" \
-d '{
"refreshToken": "{refreshToken}",
"deviceId": "manual-test-device-002"
}'
```
- ✅ 获得新的 access token
- ✅ 新 token 可以正常使用
### 场景 4: KYC 认证
10. **提交 KYC 信息**
```bash
curl -X POST http://localhost:3000/api/v1/user/submit-kyc \
-H "Authorization: Bearer {accessToken}" \
-H "Content-Type: application/json" \
-d '{
"realName": "张三",
"idCardNumber": "110101199001011234",
"idCardFrontUrl": "https://example.com/id-front.jpg",
"idCardBackUrl": "https://example.com/id-back.jpg"
}'
```
- ✅ 提交成功
- ✅ 查看个人资料,确认 KYC 信息存在且身份证号已脱敏
### 场景 5: 推荐系统
11. **根据推荐码查询用户**
```bash
curl -X GET http://localhost:3000/api/v1/user/by-referral-code/{referralCode}
```
- ✅ 返回正确的账户信息
12. **使用推荐码注册新用户**
```bash
curl -X POST http://localhost:3000/api/v1/user/auto-create \
-H "Content-Type: application/json" \
-d '{
"deviceId": "manual-test-device-003",
"deviceName": "Android Phone",
"provinceCode": "110000",
"cityCode": "110100",
"inviterReferralCode": "{referralCode}"
}'
```
- ✅ 创建成功
- ✅ 新用户的 inviterSequence 正确
## 边界测试
### 设备限制测试
- [ ] 添加 5 个设备 → 成功
- [ ] 尝试添加第 6 个设备 → 失败,提示设备数量限制
- [ ] 移除 1 个设备后 → 可以再添加 1 个
### 并发测试(手动)
- [ ] 两个设备同时使用同一个 refresh token → 只有一个成功
- [ ] 两个用户同时创建账户 → 账户序列号不重复
- [ ] 同一个推荐码被多人使用 → 都成功
### 异常处理测试
- [ ] 数据库连接断开 → 返回 500 错误
- [ ] Redis 连接断开 → SMS 验证码功能失败
- [ ] Kafka 连接断开 → 事件发布失败(但主流程成功)
- [ ] 网络超时 → 合理的超时提示
### 数据一致性测试
- [ ] 创建账户失败(如数据库错误)→ 账户序列号不会被消耗
- [ ] 添加设备失败(如超过限制)→ 数据库没有脏数据
- [ ] Token 生成失败 → 账户仍然创建成功,可以重新登录
## 真实环境测试
### 部署到测试环境
- [ ] Docker Compose 一键启动
- [ ] Kubernetes 部署
- [ ] 环境变量配置正确
- [ ] 数据库迁移成功
- [ ] 健康检查端点响应正常
### 监控和日志
- [ ] 日志正确输出到文件/控制台
- [ ] 错误日志包含堆栈信息
- [ ] 性能指标可以被 Prometheus 采集
- [ ] 日志可以被 ELK/Loki 采集
### 备份和恢复
- [ ] 数据库备份
- [ ] 数据恢复测试
- [ ] 灾难恢复演练

View File

@ -0,0 +1,56 @@
# 性能测试计划
## 工具推荐
- **Artillery** - HTTP 负载测试
- **K6** - 现代化负载测试工具
- **Apache JMeter** - 传统但功能强大
## 测试场景
### 1. 账户创建性能
```bash
# 使用 k6 测试
k6 run --vus 100 --duration 30s account-creation-test.js
```
- 目标100 并发用户,持续 30 秒
- 指标:
- 平均响应时间 < 500ms
- P95 响应时间 < 1000ms
- 错误率 < 0.1%
- TPS (每秒事务数) > 200
### 2. 登录/刷新 Token 性能
- 目标200 并发用户
- 指标:
- 平均响应时间 < 200ms
- P95 < 500ms
### 3. 助记词恢复性能
- 目标50 并发用户(计算密集型操作)
- 指标:
- 平均响应时间 < 2000ms
- 不应该阻塞其他请求
### 4. 数据库连接池测试
- 测试连接池耗尽场景
- 测试连接泄漏检测
### 5. 内存泄漏测试
- 长时间运行测试24小时
- 监控内存使用趋势
## 压力测试
```bash
# 逐步增加负载直到系统崩溃
k6 run --stages \
"5m:100" \ # 5分钟内增加到100用户
"10m:500" \ # 10分钟内增加到500用户
"5m:1000" \ # 5分钟内增加到1000用户
"10m:0" \ # 10分钟内降回0
stress-test.js
```
找到系统的极限:
- 最大并发用户数
- 最大 TPS
- 崩溃点

View File

@ -0,0 +1,138 @@
# 安全测试检查清单
## 自动化安全扫描工具
### 1. OWASP ZAP
```bash
# Docker 运行 ZAP 扫描
docker run -v $(pwd):/zap/wrk/:rw \
-t owasp/zap2docker-stable zap-baseline.py \
-t http://localhost:3000 -g gen.conf -r testreport.html
```
### 2. npm audit
```bash
npm audit
npm audit fix
```
### 3. Snyk
```bash
npm install -g snyk
snyk test
snyk monitor
```
## 手动安全测试
### 认证和授权
- [ ] **JWT Token 安全**
- [ ] Token 在 URL 中不可见(只在 Header
- [ ] Token 过期时间合理access: 15min, refresh: 7天
- [ ] Refresh token 轮换(用过的不能再用)
- [ ] Token 包含最小必要信息
- [ ] Token 签名算法安全HS256/RS256
- [ ] **设备授权**
- [ ] 未授权设备无法使用 token
- [ ] 设备绑定无法伪造
- [ ] 设备限制最多5个有效
- [ ] **会话管理**
- [ ] 登出后 token 立即失效
- [ ] 移除设备后该设备的 token 失效
- [ ] 冻结账户后所有 token 失效
### 输入验证
- [ ] **SQL 注入测试**
```sql
phoneNumber: "13800138000' OR '1'='1"
nickname: "'; DROP TABLE users; --"
```
- [ ] **NoSQL 注入测试**
```json
{"accountSequence": {"$gt": 0}}
```
- [ ] **XSS 攻击测试**
```javascript
nickname: "<script>alert('XSS')</script>"
avatarUrl: "javascript:alert('XSS')"
```
- [ ] **命令注入测试**
```bash
deviceName: "; rm -rf /"
```
- [ ] **路径遍历测试**
```
avatarUrl: "../../etc/passwd"
```
### 业务逻辑漏洞
- [ ] **助记词安全**
- [ ] 助记词不在日志中出现
- [ ] 助记词传输加密HTTPS
- [ ] 助记词存储加密
- [ ] 助记词不在错误信息中泄露
- [ ] **身份证号安全**
- [ ] 返回时必须脱敏
- [ ] 数据库加密存储
- [ ] 不在日志中记录完整身份证号
- [ ] **暴力破解防护**
- [ ] 登录失败次数限制
- [ ] SMS 验证码尝试次数限制
- [ ] 账户序列号枚举防护
- [ ] 验证码发送频率限制
- [ ] **重放攻击防护**
- [ ] API 请求幂等性
- [ ] Nonce/时间戳验证
- [ ] **越权访问测试**
- [ ] 用户 A 无法访问用户 B 的数据
- [ ] 用户 A 无法修改用户 B 的设备
- [ ] 普通用户无法访问管理员接口
### 敏感数据保护
- [ ] **传输安全**
- [ ] 强制 HTTPS
- [ ] TLS 1.2+
- [ ] 安全的 Cipher Suite
- [ ] **存储安全**
- [ ] 密码使用 bcrypt/argon2 加密
- [ ] 助记词 AES-256-GCM 加密
- [ ] 身份证号加密存储
- [ ] 数据库连接字符串不在代码中
- [ ] **日志安全**
- [ ] 日志不包含密码
- [ ] 日志不包含完整助记词
- [ ] 日志不包含完整身份证号
- [ ] 日志不包含完整银行卡号
### CORS 和 CSRF
- [ ] CORS 白名单配置正确
- [ ] CSRF Token 验证(如果有 Web 前端)
- [ ] SameSite Cookie 设置
### 速率限制
- [ ] 全局速率限制100 req/min per IP
- [ ] 登录接口限制5 次失败锁定 15 分钟)
- [ ] SMS 发送限制1 次/分钟, 5 次/小时, 10 次/天)
- [ ] 账户创建限制1 个/IP/天)
### 依赖安全
- [ ] 所有依赖是最新稳定版
- [ ] 没有已知的 CVE 漏洞
- [ ] 定期更新依赖
## 渗透测试工具
- **Burp Suite** - 手动渗透测试
- **SQLMap** - SQL 注入自动化测试
- **Postman** - API 安全测试