# 性能测试模块 - 计划执行文档

> **文档版本**: v1.0
> **创建日期**: 2026-08-12
> **关联需求**: `_PRD_性能测试模块需求文档.md`（位于 `Docs/PRD/需求文档/性能测试/`）
> **执行策略**: 分阶段迭代，每阶段可独立验证

---

## 一、执行总览

### 1.1 阶段划分

| 阶段 | 名称 | 核心交付 | 预计工期 |
|------|------|---------|---------|
| Phase 1 | 数据库模型与Schema | PerformanceTask/PerformanceSnapshot 模型 + Pydantic Schema | 1天 |
| Phase 2 | 性能测试执行引擎 | asyncio + aiohttp 并发引擎 + MetricsCollector | 2天 |
| Phase 3 | 后端路由与服务 | PerformanceService + API 路由 + WebSocket 推送 | 1天 |
| Phase 4 | 前端页面 | 任务配置 / 实时监控 / 报告页面 | 2天 |
| Phase 5 | 集成测试与验证 | 端到端测试 + 结果正确性验证 | 1天 |

### 1.2 依赖关系

```
Phase 1 (数据库模型) ──→ Phase 3 (后端路由)
                             ↑
Phase 2 (执行引擎) ────────┘
                             ↓
                    Phase 4 (前端页面) ──→ Phase 5 (集成测试)
```

### 1.3 文件清单

| 文件 | 阶段 | 说明 |
|------|------|------|
| `backend/app/models/performance.py` | Phase 1 | PerformanceTask + PerformanceSnapshot ORM |
| `backend/app/schemas/performance.py` | Phase 1 | Pydantic 校验 |
| `backend/app/executors/performance_executor.py` | Phase 2 | 性能测试执行引擎 |
| `backend/app/services/performance_service.py` | Phase 3 | 业务逻辑层 |
| `backend/app/routers/performance.py` | Phase 3 | API 路由 |
| `backend/app/database.py` | Phase 3 | 注册新表 |
| `backend/app/main.py` | Phase 3 | 注册路由 |
| `frontend/src/api/performance.ts` | Phase 4 | 前端 API 封装 |
| `frontend/src/views/performance/PerformanceTasks.vue` | Phase 4 | 任务列表页 |
| `frontend/src/views/performance/PerformanceTaskConfig.vue` | Phase 4 | 任务配置页 |
| `frontend/src/views/performance/PerformanceMonitor.vue` | Phase 4 | 实时监控页 |
| `frontend/src/views/performance/PerformanceReport.vue` | Phase 4 | 报告页 |
| `frontend/src/router/index.ts` | Phase 4 | 注册路由 |
| `frontend/src/types/performance.ts` | Phase 4 | TypeScript 类型定义 |

---

## 二、Phase 1: 数据库模型与 Schema

### 2.1 任务清单

| # | 任务 | 文件 | 说明 |
|---|------|------|------|
| 1.1 | 创建 PerformanceTask 模型 | `backend/app/models/performance.py` | 性能测试任务 ORM |
| 1.2 | 创建 PerformanceSnapshot 模型 | `backend/app/models/performance.py` | 性能快照 ORM |
| 1.3 | 创建 Pydantic Schema | `backend/app/schemas/performance.py` | 请求/响应校验 |
| 1.4 | 注册模型到 database.py | `backend/app/database.py` | 新增表初始化 |

### 2.2 详细设计

#### 2.2.1 PerformanceTask 模型

```python
class PerformanceTask(Base):
    """性能测试任务模型"""
    __tablename__ = "performance_tasks"
    
    id: str = mapped_column(String(64), primary_key=True)
    name: str = mapped_column(String(200), default="")
    description: str = mapped_column(Text, default="")
    status: str = mapped_column(String(20), default="pending")
    
    # 目标配置
    target_url: str = mapped_column(Text, default="")
    method: str = mapped_column(String(10), default="GET")
    headers: dict = mapped_column(JSON, default=dict)
    body: Optional[dict] = mapped_column(JSON, nullable=True)
    body_template: Optional[dict] = mapped_column(JSON, nullable=True)
    
    # 压测配置
    mode: str = mapped_column(String(20), default="concurrent")
    concurrency: int = mapped_column(Integer, default=10)
    qps_target: int = mapped_column(Integer, default=100)
    duration: int = mapped_column(Integer, default=60)
    ramp_up: int = mapped_column(Integer, default=10)
    step_concurrency: dict = mapped_column(JSON, default=list)
    step_duration: int = mapped_column(Integer, default=60)
    
    # 认证配置
    auth_required: bool = mapped_column(Boolean, default=True)
    account_key: str = mapped_column(String(50), default="superadmin")
    
    # 断言配置
    assertions: list = mapped_column(JSON, default=list)
    
    # 结果统计
    total_requests: int = mapped_column(Integer, default=0)
    success_count: int = mapped_column(Integer, default=0)
    fail_count: int = mapped_column(Integer, default=0)
    min_response_time: float = mapped_column(Float, default=0.0)
    max_response_time: float = mapped_column(Float, default=0.0)
    avg_response_time: float = mapped_column(Float, default=0.0)
    p50_response_time: float = mapped_column(Float, default=0.0)
    p90_response_time: float = mapped_column(Float, default=0.0)
    p99_response_time: float = mapped_column(Float, default=0.0)
    actual_tps: float = mapped_column(Float, default=0.0)
    error_rate: float = mapped_column(Float, default=0.0)
    
    # 时间
    start_time: Optional[datetime] = mapped_column(DateTime, nullable=True)
    end_time: Optional[datetime] = mapped_column(DateTime, nullable=True)
    duration_actual: float = mapped_column(Float, default=0.0)
    created_at: datetime = mapped_column(DateTime, default=datetime.utcnow)
    updated_at: datetime = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
    
    # 关联
    snapshots: list = relationship("PerformanceSnapshot", back_populates="task", cascade="all, delete-orphan")
```

#### 2.2.2 PerformanceSnapshot 模型

```python
class PerformanceSnapshot(Base):
    """性能快照模型"""
    __tablename__ = "performance_snapshots"
    
    id: int = mapped_column(Integer, primary_key=True, autoincrement=True)
    task_id: str = mapped_column(String(64), ForeignKey("performance_tasks.id"))
    timestamp: float = mapped_column(Float)
    elapsed: float = mapped_column(Float)
    concurrent_users: int = mapped_column(Integer, default=0)
    tps: float = mapped_column(Float, default=0.0)
    avg_response_time: float = mapped_column(Float, default=0.0)
    min_response_time: float = mapped_column(Float, default=0.0)
    max_response_time: float = mapped_column(Float, default=0.0)
    p50_response_time: float = mapped_column(Float, default=0.0)
    p90_response_time: float = mapped_column(Float, default=0.0)
    p99_response_time: float = mapped_column(Float, default=0.0)
    success_count: int = mapped_column(Integer, default=0)
    fail_count: int = mapped_column(Integer, default=0)
    status_2xx: int = mapped_column(Integer, default=0)
    status_3xx: int = mapped_column(Integer, default=0)
    status_4xx: int = mapped_column(Integer, default=0)
    status_5xx: int = mapped_column(Integer, default=0)
    
    task: Mapped["PerformanceTask"] = relationship("PerformanceTask", back_populates="snapshots")
```

#### 2.2.3 Schema 设计

```python
# 创建/更新任务
class PerformanceTaskCreate(BaseModel):
    name: str
    description: str = ""
    target_url: str
    method: str = "GET"
    headers: dict = {}
    body: Optional[dict] = None
    body_template: Optional[dict] = None
    mode: str = "concurrent"
    concurrency: int = 10
    qps_target: int = 100
    duration: int = 60
    ramp_up: int = 10
    step_concurrency: list = []
    step_duration: int = 60
    auth_required: bool = True
    account_key: str = "superadmin"
    assertions: list = []

# 任务列表响应
class PerformanceTaskResponse(BaseModel):
    id: str
    name: str
    status: str
    mode: str
    target_url: str
    total_requests: int
    actual_tps: float
    avg_response_time: float
    error_rate: float
    start_time: Optional[datetime]
    end_time: Optional[datetime]
    duration_actual: float
    created_at: datetime

# 执行配置
class PerformanceRunRequest(BaseModel):
    config_override: Optional[dict] = None  # 可覆盖配置项
```

---

## 三、Phase 2: 性能测试执行引擎

### 3.1 任务清单

| # | 任务 | 文件 | 说明 |
|---|------|------|------|
| 2.1 | 实现 MetricsCollector | `backend/app/executors/performance_executor.py` | 指标采集器 |
| 2.2 | 实现并发模式引擎 | `backend/app/executors/performance_executor.py` | 固定并发数压测 |
| 2.3 | 实现 QPS 模式引擎 | `backend/app/executors/performance_executor.py` | 固定 QPS 压测 |
| 2.4 | 实现阶梯模式引擎 | `backend/app/executors/performance_executor.py` | 阶梯加压 |
| 2.5 | 实现断言验证器 | `backend/app/executors/performance_executor.py` | 断言逻辑 |
| 2.6 | 实现 Token 管理 | `backend/app/executors/performance_executor.py` | 调用 HttpClient 获取 Token |

### 3.2 详细设计

#### 3.2.1 核心架构

```python
class PerformanceExecutor:
    """
    性能测试执行器
    
    轻量级 asyncio + aiohttp 自研引擎。
    与 PlaywrightExecutor(UI测试) 和 SecurityExecutor(安全测试) 并列。
    """
    
    def __init__(self, db_session, http_client_config: dict):
        self.db = db_session
        self.http_client_config = http_client_config
        self._http_client: Optional[HttpClient] = None
        self._token: Optional[str] = None
        self._running = False
        self._metrics = MetricsCollector()
        self._validator = ResultValidator()
    
    async def execute(self, task: PerformanceTask) -> dict:
        """执行性能测试任务"""
        # 1. 初始化 HttpClient 并获取 Token
        if task.auth_required:
            self._http_client = HttpClient(self.http_client_config)
            self._token = self._http_client.login(task.account_key)
        
        # 2. 根据 mode 选择执行策略
        if task.mode == "concurrent":
            return await self._run_concurrent(task)
        elif task.mode == "qps":
            return await self._run_qps(task)
        elif task.mode == "step":
            return await self._run_step(task)
    
    async def _run_concurrent(self, task: PerformanceTask):
        """并发模式：固定并发数"""
        semaphore = asyncio.Semaphore(task.concurrency)
        self._running = True
        start = time.time()
        
        async with aiohttp.ClientSession() as session:
            workers = [
                self._worker(session, task, semaphore)
                for _ in range(task.concurrency)
            ]
            # 预热阶段
            await asyncio.sleep(task.ramp_up)
            # 压测阶段
            await asyncio.sleep(task.duration)
            self._running = False
            await asyncio.gather(*workers, return_exceptions=True)
        
        return self._metrics.summary()
    
    async def _worker(self, session, task, semaphore):
        """单个工作协程"""
        while self._running:
            async with semaphore:
                await self._send_request(session, task)
    
    async def _send_request(self, session, task):
        """发送单个请求并记录指标"""
        start = time.time()
        try:
            headers = self._build_headers(task)
            async with session.request(
                task.method, task.target_url,
                headers=headers,
                json=task.body if task.method in ("POST", "PUT") else None,
                ssl=False
            ) as resp:
                status = resp.status
                body = await resp.text()
                elapsed = (time.time() - start) * 1000  # ms
                
                # 执行断言
                assert_ok = self._validator.validate(task.assertions, status, body, elapsed)
                
                # 记录指标
                self._metrics.record(status, elapsed, assert_ok)
        except Exception as e:
            elapsed = (time.time() - start) * 1000
            self._metrics.record(0, elapsed, False, str(e))
```

#### 3.2.2 MetricsCollector

```python
class MetricsCollector:
    """
    指标采集器
    
    每秒采集一次指标，支持实时查询和最终汇总。
    """
    
    def __init__(self, snapshot_callback=None):
        self.snapshot_callback = snapshot_callback
        self._lock = threading.Lock()
        self._reset()
        self._start_time = time.time()
        self._sampler_task = None
    
    def _reset(self):
        # 周期内计数
        self._period_success = 0
        self._period_fail = 0
        self._period_times = []
        self._period_status_2xx = 0
        self._period_status_3xx = 0
        self._period_status_4xx = 0
        self._period_status_5xx = 0
        
        # 全局累计
        self.total_requests = 0
        self.success_count = 0
        self.fail_count = 0
        self.all_times = []
        self.status_2xx = 0
        self.status_3xx = 0
        self.status_4xx = 0
        self.status_5xx = 0
    
    def record(self, status, elapsed_ms, success, error=""):
        """记录一次请求结果"""
        with self._lock:
            self.total_requests += 1
            if success:
                self.success_count += 1
                self._period_success += 1
            else:
                self.fail_count += 1
                self._period_fail += 1
            
            self._period_times.append(elapsed_ms)
            self.all_times.append(elapsed_ms)
            
            if 200 <= status < 300:
                self._period_status_2xx += 1
                self.status_2xx += 1
            elif 300 <= status < 400:
                self._period_status_3xx += 1
                self.status_3xx += 1
            elif 400 <= status < 500:
                self._period_status_4xx += 1
                self.status_4xx += 1
            elif status >= 500:
                self._period_status_5xx += 1
                self.status_5xx += 1
    
    def snapshot(self) -> dict:
        """采集当前周期快照并重置周期计数器"""
        with self._lock:
            elapsed = time.time() - self._start_time
            period_times = self._period_times
            period_success = self._period_success
            period_fail = self._period_fail
            
            # 计算周期统计
            tps = period_success / 1.0 if period_success > 0 else 0
            avg = sum(period_times) / len(period_times) if period_times else 0
            p50 = self._percentile(period_times, 50) if period_times else 0
            p90 = self._percentile(period_times, 90) if period_times else 0
            p99 = self._percentile(period_times, 99) if period_times else 0
            
            snapshot = {
                "elapsed": round(elapsed, 1),
                "tps": round(tps, 2),
                "avg_response_time": round(avg, 2),
                "min_response_time": round(min(period_times), 2) if period_times else 0,
                "max_response_time": round(max(period_times), 2) if period_times else 0,
                "p50": round(p50, 2),
                "p90": round(p90, 2),
                "p99": round(p99, 2),
                "success_count": period_success,
                "fail_count": period_fail,
                "status_2xx": self._period_status_2xx,
                "status_3xx": self._period_status_3xx,
                "status_4xx": self._period_status_4xx,
                "status_5xx": self._period_status_5xx,
                "total_requests": self.total_requests,
            }
            
            # 重置周期计数器
            self._period_success = 0
            self._period_fail = 0
            self._period_times = []
            self._period_status_2xx = 0
            self._period_status_3xx = 0
            self._period_status_4xx = 0
            self._period_status_5xx = 0
            
            return snapshot
    
    def summary(self) -> dict:
        """最终汇总统计"""
        times = self.all_times
        return {
            "total_requests": self.total_requests,
            "success_count": self.success_count,
            "fail_count": self.fail_count,
            "error_rate": round(self.fail_count / max(self.total_requests, 1) * 100, 2),
            "min_response_time": round(min(times), 2) if times else 0,
            "max_response_time": round(max(times), 2) if times else 0,
            "avg_response_time": round(sum(times) / len(times), 2) if times else 0,
            "p50": round(self._percentile(times, 50), 2) if times else 0,
            "p90": round(self._percentile(times, 90), 2) if times else 0,
            "p99": round(self._percentile(times, 99), 2) if times else 0,
            "actual_tps": round(self.success_count / max(time.time() - self._start_time, 1), 2),
            "status_2xx": self.status_2xx,
            "status_3xx": self.status_3xx,
            "status_4xx": self.status_4xx,
            "status_5xx": self.status_5xx,
        }
    
    def _percentile(self, data, p):
        """计算百分位数"""
        if not data:
            return 0
        sorted_data = sorted(data)
        k = (len(sorted_data) - 1) * p / 100
        f = int(k)
        c = f + 1 if f + 1 < len(sorted_data) else f
        return sorted_data[f] + (sorted_data[c] - sorted_data[f]) * (k - f)
```

#### 3.2.3 ResultValidator

```python
class ResultValidator:
    """结果验证器：执行断言规则"""
    
    def validate(self, assertions: list, status_code: int, body: str, response_time: float) -> bool:
        """
        执行所有断言，全部通过返回 True
        
        Args:
            assertions: 断言规则列表
            status_code: HTTP 状态码
            body: 响应体文本
            response_time: 响应时间（ms）
        
        Returns:
            bool: 所有断言通过返回 True
        """
        if not assertions:
            return True
        
        for assertion in assertions:
            if not self._evaluate(assertion, status_code, body, response_time):
                return False
        return True
    
    def _evaluate(self, assertion: dict, status_code: int, body: str, response_time: float) -> bool:
        """评估单条断言"""
        atype = assertion.get("type")
        operator = assertion.get("operator")
        value = assertion.get("value")
        
        if atype == "status_code":
            actual = status_code
        elif atype == "response_time":
            actual = response_time
        elif atype == "response_body":
            return self._check_body(assertion, body)
        else:
            return True
        
        return self._compare(actual, operator, value)
    
    def _compare(self, actual, operator, expected) -> bool:
        """比较运算符"""
        if operator == "equals":
            return actual == expected
        elif operator == "not_equals":
            return actual != expected
        elif operator == "less_than":
            return actual < expected
        elif operator == "less_or_equal":
            return actual <= expected
        elif operator == "greater_than":
            return actual > expected
        elif operator == "greater_or_equal":
            return actual >= expected
        return True
```

#### 3.2.4 Token 与认证管理

通过复用 HttpClient 的 login() 方法获取 Token：

```python
def _ensure_token(self, task: PerformanceTask) -> str:
    """确保有有效的 Token"""
    if not self._http_client:
        self._http_client = HttpClient(self.http_client_config)
    
    if not self._token:
        self._token = self._http_client.login(task.account_key)
    
    return self._token

def _build_headers(self, task: PerformanceTask) -> dict:
    """构造请求头（含签名）"""
    headers = dict(task.headers) if task.headers else {}
    headers.setdefault("Content-Type", "application/json")
    headers.setdefault("Accept", "application/json, text/plain, */*")
    
    if task.auth_required and self._token:
        headers["Authorization"] = f"Bearer {self._token}"
    
    return headers
```

---

## 四、Phase 3: 后端路由与服务

### 4.1 任务清单

| # | 任务 | 文件 | 说明 |
|---|------|------|------|
| 3.1 | 实现 PerformanceService | `backend/app/services/performance_service.py` | CRUD + 执行逻辑 |
| 3.2 | 实现性能测试路由 | `backend/app/routers/performance.py` | API 端点 |
| 3.3 | 注册模型到 database.py | `backend/app/database.py` | 导入 PerformanceTask/PerformanceSnapshot |
| 3.4 | 注册路由到 main.py | `backend/app/main.py` | 注册 performance 路由 |

### 4.2 API 设计

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/performance/tasks` | 获取任务列表 |
| POST | `/api/performance/tasks` | 创建任务 |
| GET | `/api/performance/tasks/{id}` | 获取任务详情 |
| PUT | `/api/performance/tasks/{id}` | 更新任务 |
| DELETE | `/api/performance/tasks/{id}` | 删除任务 |
| POST | `/api/performance/tasks/{id}/run` | 执行任务 |
| POST | `/api/performance/tasks/{id}/stop` | 停止任务 |
| GET | `/api/performance/tasks/{id}/snapshots` | 获取快照数据 |
| GET | `/api/performance/tasks/{id}/report` | 获取报告数据 |
| GET | `/api/performance/tasks/{id}/results` | 获取执行结果详情 |

### 4.3 WebSocket 端点

| 路径 | 说明 |
|------|------|
| `/api/performance/ws/{task_id}` | 性能测试实时监控 |

WebSocket 消息类型与 PRD 3.4 节一致。

### 4.4 Service 核心逻辑

```python
class PerformanceService:
    """性能测试服务"""
    
    async def create_task(self, data: dict) -> PerformanceTask:
        """创建性能测试任务"""
        task = PerformanceTask(id=generate_id("perf"), **data)
        self.db.add(task)
        await self.db.commit()
        await self.db.refresh(task)
        return task
    
    async def run_task(self, task_id: str, config_override: dict = None) -> dict:
        """执行性能测试任务"""
        task = await self._get_task(task_id)
        task.status = "running"
        task.start_time = datetime.now()
        await self.db.flush()
        
        # 在后台线程中执行（避免阻塞事件循环）
        loop = asyncio.get_event_loop()
        result = await loop.run_in_executor(
            None, self._run_sync, task, config_override
        )
        
        # 更新任务结果
        task.status = "completed"
        task.end_time = datetime.now()
        task.duration_actual = (task.end_time - task.start_time).total_seconds()
        # 更新统计字段...
        await self.db.commit()
        
        return task.to_dict()
    
    def _run_sync(self, task, config_override):
        """同步执行包装器（在后台线程运行）"""
        asyncio.set_event_loop(None)  # 避免与 FastAPI 事件循环冲突
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        try:
            executor = PerformanceExecutor(...)
            result = loop.run_until_complete(executor.execute(task))
            return result
        finally:
            loop.close()
```

---

## 五、Phase 4: 前端页面

### 5.1 任务清单

| # | 任务 | 文件 | 说明 |
|---|------|------|------|
| 4.1 | 创建 TypeScript 类型定义 | `frontend/src/types/performance.ts` | 接口类型 |
| 4.2 | 创建 API 封装 | `frontend/src/api/performance.ts` | axios 调用 |
| 4.3 | 创建任务列表页 | `frontend/src/views/performance/PerformanceTasks.vue` | 列表+操作 |
| 4.4 | 创建任务配置页 | `frontend/src/views/performance/PerformanceTaskConfig.vue` | 新建/编辑 |
| 4.5 | 创建实时监控页 | `frontend/src/views/performance/PerformanceMonitor.vue` | 实时图表 |
| 4.6 | 创建报告页 | `frontend/src/views/performance/PerformanceReport.vue` | 报告展示 |
| 4.7 | 注册路由 | `frontend/src/router/index.ts` | 添加性能测试路由 |

### 5.2 路由设计

```typescript
{
  path: '/performance',
  name: 'Performance',
  redirect: '/performance/tasks',
  meta: { title: '性能测试', icon: 'Speed' },
  children: [
    {
      path: 'tasks',
      name: 'PerformanceTasks',
      component: () => import('@/views/performance/PerformanceTasks.vue'),
      meta: { title: '任务管理' }
    },
    {
      path: 'tasks/config/:id?',
      name: 'PerformanceTaskConfig',
      component: () => import('@/views/performance/PerformanceTaskConfig.vue'),
      meta: { title: '任务配置', hidden: true }
    },
    {
      path: 'monitor/:id',
      name: 'PerformanceMonitor',
      component: () => import('@/views/performance/PerformanceMonitor.vue'),
      meta: { title: '实时监控', hidden: true }
    },
    {
      path: 'report/:id',
      name: 'PerformanceReport',
      component: () => import('@/views/performance/PerformanceReport.vue'),
      meta: { title: '测试报告', hidden: true }
    }
  ]
}
```

### 5.3 页面设计要点

#### 5.3.1 任务列表页 (PerformanceTasks.vue)

- 表格展示：名称、目标URL、压测模式、状态、TPS、平均响应时间、错误率、创建时间
- 操作按钮：新建、执行、查看报告、删除
- 状态标签：pending/running/completed/failed/cancelled
- 搜索和筛选：按名称搜索、按状态筛选

#### 5.3.2 任务配置页 (PerformanceTaskConfig.vue)

- 基本信息：名称、描述
- 目标配置：URL、方法选择器(GET/POST/PUT/DELETE)、请求头(JSON编辑器)、请求体(JSON编辑器)
- 压测模式选择：Tab 切换
  - 并发模式：并发数、时长、预热时间
  - QPS模式：目标QPS、时长
  - 阶梯模式：阶梯并发数组(JSON)、每阶梯时长
- 认证配置：是否需要登录、账号选择(superadmin/admin/user)
- 断言配置：可增删改的断言规则列表
- 保存/取消按钮

#### 5.3.3 实时监控页 (PerformanceMonitor.vue)

- 顶部统计面板：总请求数、当前TPS、平均响应时间、错误率、已用时间
- 实时曲线图（使用 ECharts）：
  - TPS 曲线（最近60秒滑动窗口）
  - 响应时间曲线（平均/P50/P90/P99）
  - 并发数曲线
  - 状态码分布柱状图
- 停止按钮

#### 5.3.4 报告页 (PerformanceReport.vue)

- 执行概览卡片
- 统计图表区
- 详细数据表格
- 导出按钮（Markdown/JSON）

---

## 六、Phase 5: 集成测试与验证

### 6.1 任务清单

| # | 任务 | 说明 |
|---|------|------|
| 5.1 | 端到端流程测试 | 创建任务→执行→查看监控→查看报告 |
| 5.2 | 断言正确性验证 | 验证断言逻辑是否正确 |
| 5.3 | 三种模式测试 | 并发/QPS/阶梯模式分别验证 |
| 5.4 | 错误场景测试 | Token过期、网络超时、目标不可达 |

### 6.2 验证标准

| 检查项 | 验证方法 | 通过标准 |
|--------|---------|---------|
| 任务创建 | API 调用 | 返回任务ID，数据库可查 |
| 任务执行 | API 调用 | 状态变为 running→completed |
| 实时推送 | WebSocket | 每秒收到 snapshot 消息 |
| 指标正确性 | 手动验证 | TPS ≈ 成功数/时间 |
| 断言验证 | 故意注入错误断言 | 断言失败时计入错误计数 |
| 报告生成 | API 调用 | 返回完整统计数据 |
| 页面渲染 | 前端访问 | 各页面正常显示 |

---

## 七、技术选型说明

### 7.1 为什么用 aiohttp 而非 requests

| 对比项 | requests | aiohttp |
|--------|----------|---------|
| 并发模型 | 线程池 | asyncio 协程 |
| 并发性能 | 受限于 GIL 和线程数 | 单线程可处理数千并发 |
| 资源开销 | 每线程 ~8MB 栈 | 每协程 ~1KB |
| 适用场景 | 低并发(<100) | 高并发(100~5000+) |

性能测试需要模拟高并发场景，aiohttp 是更合适的选择。

### 7.2 为什么自研而非 JMeter/Locust

| 对比项 | JMeter | Locust | 自研引擎 |
|--------|--------|--------|---------|
| 集成复杂度 | 需独立进程+文件接口 | 需独立进程+消息队列 | 直接嵌入平台 |
| 认证适配 | 需编写 Java 插件 | 需编写 Python 钩子 | 直接复用 HttpClient |
| 实时推送 | 需额外配置 | 需额外配置 | 原生 WebSocket |
| 部署依赖 | 需 JDK | 需独立安装 | 零额外依赖 |

自研引擎可无缝集成到现有平台，复用已有认证和报告能力。

---

## 八、风险与应对

| 风险 | 阶段 | 应对 |
|------|------|------|
| aiohttp 在 Windows 上事件循环冲突 | Phase 2 | 使用 `run_in_executor` + 独立事件循环，参考 PlaywrightExecutor 模式 |
| 高并发时 SQLite 写入瓶颈 | Phase 3 | 快照批量写入，每5秒持久化一次 |
| 前端图表性能 | Phase 4 | 使用 ECharts 大数据量模式，限制显示最近300个数据点 |
| 被测系统防火墙拦截 | Phase 5 | 配置合理的请求频率，避免触发 WAF |

---

*本文档为性能测试模块的执行计划，各阶段按顺序实施，每阶段完成后验证再进入下一阶段。*