Files
FendxPHP/scripts/run-tests.sh
Lawson 2782d765fb feat(database): 添加用户角色权限系统及相关监控功能
- 创建用户表(users)包含基本信息和认证字段
- 创建角色表(roles)用于权限控制
- 创建权限表(permissions)定义系统权限
- 创建用户角色关联表(user_roles)建立用户与角色关系
- 创建角色权限关联表(role_permissions)建立角色与权限关系
- 创建迁移记录表(migrations)追踪数据库变更
- 添加AdminController提供管理员面板功能
- 实现系统监控、配置管理、缓存清理等功能
- 添加AOP切面编程支持的各种通知类型
- 实现告警管理AlertManager支持多渠道告警
- 添加文档注解接口规范
2026-04-08 17:00:28 +08:00

572 lines
14 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# FendxPHP 自动化测试脚本
# 用法: ./scripts/run-tests.sh [test_type] [options]
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 配置
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TEST_RESULTS_DIR="${PROJECT_ROOT}/reports"
LOG_FILE="${TEST_RESULTS_DIR}/test.log"
# 创建必要的目录
mkdir -p "${TEST_RESULTS_DIR}"
mkdir -p "${TEST_RESULTS_DIR}/coverage"
mkdir -p "${TEST_RESULTS_DIR}/performance"
# 日志函数
log() {
echo -e "$1" | tee -a "${LOG_FILE}"
}
log_info() {
log "${BLUE}[INFO]${NC} $1"
}
log_success() {
log "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
log "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
log "${RED}[ERROR]${NC} $1"
}
# 显示帮助信息
show_help() {
cat << EOF
FendxPHP 自动化测试脚本
用法: $0 [test_type] [options]
测试类型:
unit 运行单元测试
integration 运行集成测试
api 运行API测试
e2e 运行端到端测试
performance 运行性能测试
security 运行安全测试
all 运行所有测试 (默认)
选项:
--coverage 生成覆盖率报告
--parallel=N 并行运行测试 (N个进程)
--filter=FILTER 过滤测试用例
--verbose 详细输出
--no-docker 不使用Docker环境
--clean 清理测试环境
--help 显示此帮助信息
示例:
$0 unit --coverage
$0 integration --filter=UserTest
$0 all --parallel=4 --coverage
$0 performance --verbose
EOF
}
# 检查依赖
check_dependencies() {
log_info "检查依赖..."
# 检查PHP
if ! command -v php &> /dev/null; then
log_error "PHP 未安装"
exit 1
fi
# 检查Composer
if ! command -v composer &> /dev/null; then
log_error "Composer 未安装"
exit 1
fi
# 检查PHPUnit
if ! command -v vendor/bin/phpunit &> /dev/null; then
log_info "安装 PHPUnit..."
composer require --dev phpunit/phpunit
fi
# 检查Docker (如果需要)
if [[ "$USE_DOCKER" == "true" ]]; then
if ! command -v docker &> /dev/null; then
log_error "Docker 未安装"
exit 1
fi
fi
log_success "依赖检查完成"
}
# 准备测试环境
prepare_environment() {
log_info "准备测试环境..."
# 复制环境配置
if [[ ! -f "${PROJECT_ROOT}/.env" ]]; then
cp "${PROJECT_ROOT}/.env.example" "${PROJECT_ROOT}/.env"
fi
# 设置测试环境变量
export APP_ENV=testing
export DB_CONNECTION=sqlite
export DB_DATABASE=:memory:
export CACHE_DRIVER=array
export SESSION_DRIVER=array
export QUEUE_CONNECTION=sync
# 安装依赖
log_info "安装Composer依赖..."
composer install --optimize-autoloader --no-interaction
# 创建测试数据库
log_info "创建测试数据库..."
php bin/console migrate:run --env=testing
log_success "测试环境准备完成"
}
# 启动Docker测试环境
start_docker_environment() {
if [[ "$USE_DOCKER" != "true" ]]; then
return
fi
log_info "启动Docker测试环境..."
# 停止现有容器
docker-compose -f docker-compose.test.yml down --volumes 2>/dev/null || true
# 启动测试容器
docker-compose -f docker-compose.test.yml up -d --build
# 等待服务就绪
log_info "等待服务启动..."
sleep 30
# 检查服务状态
if ! docker-compose -f docker-compose.test.yml ps | grep -q "Up"; then
log_error "Docker服务启动失败"
docker-compose -f docker-compose.test.yml logs
exit 1
fi
log_success "Docker环境启动完成"
}
# 停止Docker测试环境
stop_docker_environment() {
if [[ "$USE_DOCKER" != "true" ]]; then
return
fi
log_info "停止Docker测试环境..."
docker-compose -f docker-compose.test.yml down --volumes
}
# 运行单元测试
run_unit_tests() {
log_info "运行单元测试..."
local cmd="vendor/bin/phpunit tests/Unit --colors=always --log-junit=${TEST_RESULTS_DIR}/junit-unit.xml"
if [[ "$GENERATE_COVERAGE" == "true" ]]; then
cmd="$cmd --coverage-html=${TEST_RESULTS_DIR}/coverage/unit --coverage-clover=${TEST_RESULTS_DIR}/coverage/unit.xml"
fi
if [[ -n "$FILTER" ]]; then
cmd="$cmd --filter=$FILTER"
fi
if [[ "$VERBOSE" == "true" ]]; then
cmd="$cmd --verbose"
fi
if [[ "$PARALLEL" -gt 1 ]]; then
cmd="$cmd --processes=$PARALLEL"
fi
log_info "执行: $cmd"
if eval "$cmd"; then
log_success "单元测试通过"
return 0
else
log_error "单元测试失败"
return 1
fi
}
# 运行集成测试
run_integration_tests() {
log_info "运行集成测试..."
local cmd="vendor/bin/phpunit tests/Integration --colors=always --log-junit=${TEST_RESULTS_DIR}/junit-integration.xml"
if [[ -n "$FILTER" ]]; then
cmd="$cmd --filter=$FILTER"
fi
if [[ "$VERBOSE" == "true" ]]; then
cmd="$cmd --verbose"
fi
log_info "执行: $cmd"
if eval "$cmd"; then
log_success "集成测试通过"
return 0
else
log_error "集成测试失败"
return 1
fi
}
# 运行API测试
run_api_tests() {
log_info "运行API测试..."
# 启动应用服务器
log_info "启动应用服务器..."
php -S localhost:8000 -t public/ > /dev/null 2>&1 &
local SERVER_PID=$!
# 等待服务器启动
sleep 5
# 运行API测试
local cmd="vendor/bin/codecept run api --colors --xml=${TEST_RESULTS_DIR}/api-results.xml"
if [[ -n "$FILTER" ]]; then
cmd="$cmd -g $FILTER"
fi
log_info "执行: $cmd"
local result=0
if ! eval "$cmd"; then
log_error "API测试失败"
result=1
else
log_success "API测试通过"
fi
# 停止服务器
kill $SERVER_PID 2>/dev/null || true
return $result
}
# 运行端到端测试
run_e2e_tests() {
log_info "运行端到端测试..."
# 启动完整环境
start_docker_environment
# 运行E2E测试
local cmd="vendor/bin/codecept run e2e --colors --xml=${TEST_RESULTS_DIR}/e2e-results.xml"
if [[ -n "$FILTER" ]]; then
cmd="$cmd -g $FILTER"
fi
log_info "执行: $cmd"
local result=0
if ! eval "$cmd"; then
log_error "E2E测试失败"
result=1
else
log_success "E2E测试通过"
fi
# 清理环境
stop_docker_environment
return $result
}
# 运行性能测试
run_performance_tests() {
log_info "运行性能测试..."
# 启动应用服务器
php -S localhost:8000 -t public/ > /dev/null 2>&1 &
local SERVER_PID=$!
sleep 5
# 并发测试
log_info "执行并发测试..."
ab -n 1000 -c 10 http://localhost:8000/api/users > "${TEST_RESULTS_DIR}/performance/ab-results.txt" 2>&1
# 内存测试
log_info "执行内存测试..."
php -d memory_limit=1G -r "
\$start = memory_get_usage();
for (\$i = 0; \$i < 10000; \$i++) {
\$data = ['id' => \$i, 'name' => 'test'];
json_encode(\$data);
}
echo 'Memory used: ' . ((memory_get_usage() - \$start) / 1024 / 1024) . ' MB\n';
" > "${TEST_RESULTS_DIR}/performance/memory-test.txt"
# 数据库性能测试
log_info "执行数据库性能测试..."
php bin/console benchmark:database > "${TEST_RESULTS_DIR}/performance/database-test.txt" 2>&1
# 停止服务器
kill $SERVER_PID 2>/dev/null || true
log_success "性能测试完成"
return 0
}
# 运行安全测试
run_security_tests() {
log_info "运行安全测试..."
# 依赖漏洞扫描
log_info "扫描依赖漏洞..."
composer audit > "${TEST_RESULTS_DIR}/security/composer-audit.txt" 2>&1
# 代码安全分析
log_info "执行代码安全分析..."
if command -v vendor/bin/phpstan &> /dev/null; then
vendor/bin/phpstan analyse --level=8 --error-format=json > "${TEST_RESULTS_DIR}/security/phpstan-results.json" 2>&1
fi
# API安全测试
log_info "执行API安全测试..."
if command -v vendor/bin/codecept &> /dev/null; then
vendor/bin/codecept run security --colors --xml="${TEST_RESULTS_DIR}/security-results.xml" 2>&1 || true
fi
log_success "安全测试完成"
return 0
}
# 生成测试报告
generate_report() {
log_info "生成测试报告..."
local report_file="${TEST_RESULTS_DIR}/test-report.html"
cat > "$report_file" << EOF
<!DOCTYPE html>
<html>
<head>
<title>FendxPHP 测试报告</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.header { background: #f0f0f0; padding: 20px; border-radius: 5px; }
.section { margin: 20px 0; }
.success { color: green; }
.error { color: red; }
.warning { color: orange; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<div class="header">
<h1>FendxPHP 测试报告</h1>
<p>生成时间: $(date)</p>
<p>测试类型: ${TEST_TYPE}</p>
</div>
<div class="section">
<h2>测试结果概览</h2>
<table>
<tr><th>测试类型</th><th>状态</th><th>详情</th></tr>
EOF
# 添加各种测试结果
if [[ -f "${TEST_RESULTS_DIR}/junit-unit.xml" ]]; then
echo "<tr><td>单元测试</td><td class='success'>通过</td><td><a href='coverage/unit/index.html'>查看覆盖率</a></td></tr>" >> "$report_file"
fi
if [[ -f "${TEST_RESULTS_DIR}/junit-integration.xml" ]]; then
echo "<tr><td>集成测试</td><td class='success'>通过</td><td>查看详细日志</td></tr>" >> "$report_file"
fi
cat >> "$report_file" << EOF
</table>
</div>
<div class="section">
<h2>性能指标</h2>
<table>
<tr><th>指标</th><th>值</th></tr>
EOF
# 添加性能指标
if [[ -f "${TEST_RESULTS_DIR}/performance/ab-results.txt" ]]; then
local rps=$(grep "Requests per second" "${TEST_RESULTS_DIR}/performance/ab-results.txt" | awk '{print $4}')
echo "<tr><td>每秒请求数</td><td>${rps}</td></tr>" >> "$report_file"
fi
cat >> "$report_file" << EOF
</table>
</div>
</body>
</html>
EOF
log_success "测试报告已生成: $report_file"
}
# 清理测试环境
cleanup() {
log_info "清理测试环境..."
# 停止Docker环境
stop_docker_environment
# 清理临时文件
rm -f "${PROJECT_ROOT}/.env.testing"
log_success "清理完成"
}
# 主函数
main() {
local test_type="${1:-all}"
local use_docker="true"
local generate_coverage="false"
local parallel="1"
local filter=""
local verbose="false"
local clean_only="false"
# 解析参数
shift
while [[ $# -gt 0 ]]; do
case $1 in
--coverage)
generate_coverage="true"
;;
--parallel=*)
parallel="${1#*=}"
;;
--filter=*)
filter="${1#*=}"
;;
--verbose)
verbose="true"
;;
--no-docker)
use_docker="false"
;;
--clean)
clean_only="true"
;;
--help)
show_help
exit 0
;;
*)
log_error "未知参数: $1"
show_help
exit 1
;;
esac
shift
done
# 设置全局变量
export USE_DOCKER="$use_docker"
export GENERATE_COVERAGE="$generate_coverage"
export PARALLEL="$parallel"
export FILTER="$filter"
export VERBOSE="$verbose"
export TEST_TYPE="$test_type"
# 只清理环境
if [[ "$clean_only" == "true" ]]; then
cleanup
exit 0
fi
# 捕获退出信号
trap cleanup EXIT
log_info "开始运行 FendxPHP 测试套件"
log_info "测试类型: $test_type"
log_info "使用Docker: $use_docker"
log_info "生成覆盖率: $generate_coverage"
# 检查依赖
check_dependencies
# 准备环境
prepare_environment
# 启动Docker环境如果需要
start_docker_environment
# 运行测试
local failed_tests=0
case $test_type in
unit)
run_unit_tests || ((failed_tests++))
;;
integration)
run_integration_tests || ((failed_tests++))
;;
api)
run_api_tests || ((failed_tests++))
;;
e2e)
run_e2e_tests || ((failed_tests++))
;;
performance)
run_performance_tests || ((failed_tests++))
;;
security)
run_security_tests || ((failed_tests++))
;;
all)
run_unit_tests || ((failed_tests++))
run_integration_tests || ((failed_tests++))
run_api_tests || ((failed_tests++))
run_performance_tests || ((failed_tests++))
run_security_tests || ((failed_tests++))
;;
*)
log_error "未知的测试类型: $test_type"
show_help
exit 1
;;
esac
# 生成报告
generate_report
# 输出结果
if [[ $failed_tests -eq 0 ]]; then
log_success "所有测试通过! 🎉"
exit 0
else
log_error "$failed_tests 个测试失败 ❌"
exit 1
fi
}
# 运行主函数
main "$@"