This commit is contained in:
parent
fbcef7aba2
commit
4cdd0b07b9
|
|
@ -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. 🔵 **持续进行**: 代码质量检查、覆盖率提升
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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 是原子性的
|
||||
- [ ] 没有提交敏感信息
|
||||
- [ ] 分支策略清晰
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# 集成测试检查清单
|
||||
|
||||
## 数据库集成测试
|
||||
- [ ] PostgreSQL 真实连接测试
|
||||
- [ ] 事务回滚测试
|
||||
- [ ] 并发写入测试(多个账户同时创建)
|
||||
- [ ] 账户序列号生成器的并发安全性
|
||||
- [ ] 外键约束测试
|
||||
- [ ] 索引性能测试
|
||||
|
||||
## Redis 集成测试
|
||||
- [ ] Redis 真实连接测试
|
||||
- [ ] Token 存储/读取/过期
|
||||
- [ ] SMS 验证码存储/过期
|
||||
- [ ] 分布式锁测试(防止重复注册)
|
||||
|
||||
## Kafka 集成测试
|
||||
- [ ] Kafka 真实连接测试
|
||||
- [ ] 事件发布成功
|
||||
- [ ] 事件发布失败重试
|
||||
- [ ] 事件顺序保证
|
||||
- [ ] 消费者能正确接收事件
|
||||
|
||||
## SMS 服务集成测试
|
||||
- [ ] 真实 SMS API 调用(使用测试号码)
|
||||
- [ ] 发送成功
|
||||
- [ ] 发送失败处理
|
||||
- [ ] 限流测试(防止恶意发送)
|
||||
|
||||
## JWT Token 测试
|
||||
- [ ] Token 签名验证
|
||||
- [ ] Token 过期验证
|
||||
- [ ] Token 刷新流程
|
||||
- [ ] 跨服务 Token 验证(如果有多个服务)
|
||||
|
||||
## 区块链钱包测试
|
||||
- [ ] 助记词生成的随机性
|
||||
- [ ] 地址派生的一致性
|
||||
- [ ] 加密/解密的安全性
|
||||
- [ ] 多链地址格式验证
|
||||
|
|
@ -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 采集
|
||||
|
||||
### 备份和恢复
|
||||
- [ ] 数据库备份
|
||||
- [ ] 数据恢复测试
|
||||
- [ ] 灾难恢复演练
|
||||
|
|
@ -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
|
||||
- 崩溃点
|
||||
|
|
@ -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 安全测试
|
||||
Loading…
Reference in New Issue