Files
ai_wht_B/测试整体后端接口性能.py
“shengyudong” 5a384b694e 2026-1-6
2026-01-06 14:18:39 +08:00

2534 lines
99 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
整合后端接口性能测试工具
整合了所有10个模块的接口测试
1. 基础接口 (flask_wht_server_api.py)
2. 认证接口 (auth_routes.py)
3. 工作台接口 (dashboard_routes.py)
4. 企业接口 (enterprise_routes.py)
5. 图片接口 (image_routes.py)
6. 日志接口 (log_routes.py)
7. 文章接口 (article_routes.py)
8. 员工接口 (employee_routes.py)
9. 作者接口 (author_routes.py)
10. 搜索服务接口 (flask_wht_server_search.py)
"""
import requests
import time
import csv
from datetime import datetime
import io
from PIL import Image
import sys
# API配置
API_BASE_URL = "http://127.0.0.1:8216" # 主服务
SEARCH_API_BASE_URL = "http://127.0.0.1:8321" # 搜索服务
USERNAME = "13621242430"
PASSWORD = "admin123"
# 测试结果存储
test_results = []
api_docs = []
# 全局token
global_token = None
# 测试模块选择(可配置)
TEST_MODULES = {
'basic': True, # 基础接口
'auth': True, # 认证接口
'dashboard': True, # 工作台
'enterprise': True, # 企业
'image': True, # 图片
'log': True, # 日志
'article': True, # 文章
'employee': True, # 员工
'author': True, # 作者
'search': False, # 搜索服务(默认关闭,需要单独服务)
}
def print_module_header(module_name, module_num, total_modules):
"""打印模块测试头部"""
print("\n" + "="*80)
print(f"[{module_num}/{total_modules}] {module_name}")
print("="*80)
def login():
"""登录获取token"""
global global_token
print("\n" + "="*80)
print("正在登录...")
url = f"{API_BASE_URL}/api/auth/login"
data = {"username": USERNAME, "password": PASSWORD}
start_time = time.time()
response = requests.post(url, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
if response.status_code == 200:
global_token = response.json()['data']['token']
print(f"✓ 登录成功,耗时: {elapsed_time:.2f}ms")
return global_token
else:
print(f"✗ 登录失败: {response.status_code}")
return None
# ============================================================================
# 模块1: 基础接口测试
# ============================================================================
def test_basic_apis():
"""测试基础接口"""
if not TEST_MODULES['basic']:
return
print_module_header("基础接口测试", 1, 10)
# 根路径
print("\n[1/3] 测试根路径...")
url = f"{API_BASE_URL}/"
for i in range(3):
try:
start_time = time.time()
response = requests.get(url, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '基础接口',
'endpoint': '/',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '基础接口',
'endpoint': '/',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 健康检查
print("[2/3] 测试健康检查...")
url = f"{API_BASE_URL}/health"
for i in range(3):
try:
start_time = time.time()
response = requests.get(url, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '基础接口',
'endpoint': '/health',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '基础接口',
'endpoint': '/health',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 404测试
print("[3/3] 测试404错误处理...")
url = f"{API_BASE_URL}/nonexistent-test"
try:
start_time = time.time()
response = requests.get(url, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '基础接口',
'endpoint': '/nonexistent-test',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 404,
'error': ''
})
except Exception as e:
test_results.append({
'module': '基础接口',
'endpoint': '/nonexistent-test',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 添加API文档
api_docs.extend([
{'module': '基础接口', 'endpoint': '/', 'method': 'GET', 'description': '根路径', 'auth': ''},
{'module': '基础接口', 'endpoint': '/health', 'method': 'GET', 'description': '健康检查', 'auth': ''},
])
# ============================================================================
# 模块2: 认证接口测试 (原脚本测试数: 11个)
# ============================================================================
def test_auth_apis(token):
"""测试认证接口 - 包含统一登录、员工登录、登出、错误场景等"""
if not TEST_MODULES['auth']:
return
print_module_header("认证接口测试", 2, 10)
# 1. 统一登录 - 用户名
print("\n[1/11] 测试统一登录(用户名)...")
url = f"{API_BASE_URL}/api/auth/login"
data = {"username": USERNAME, "password": PASSWORD}
try:
start_time = time.time()
response = requests.post(url, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/login (用户名)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/login (用户名)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 2. 统一登录 - 手机号
print("[2/11] 测试统一登录(手机号)...")
data = {"phone": USERNAME, "password": PASSWORD}
try:
start_time = time.time()
response = requests.post(url, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/login (手机号)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/login (手机号)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 3. 统一登录 - 错误密码
print("[3/11] 测试统一登录(错误密码)...")
data = {"username": USERNAME, "password": "wrong_password"}
try:
start_time = time.time()
response = requests.post(url, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/login (错误密码)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 401,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/login (错误密码)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 4. 统一登录 - 缺少参数
print("[4/11] 测试统一登录(缺少参数)...")
data = {"username": USERNAME}
try:
start_time = time.time()
response = requests.post(url, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/login (缺少参数)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 400,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/login (缺少参数)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 5. 员工登录 - 正常
print("[5/11] 测试员工登录...")
url = f"{API_BASE_URL}/api/auth/employee/login"
data = {"phone": USERNAME, "password": PASSWORD}
try:
start_time = time.time()
response = requests.post(url, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/employee/login',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/employee/login',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 6. 员工登录 - 错误密码
print("[6/11] 测试员工登录(错误密码)...")
data = {"phone": USERNAME, "password": "wrong_password"}
try:
start_time = time.time()
response = requests.post(url, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/employee/login (错误密码)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 401,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/employee/login (错误密码)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 7. 登出 - 带token
print("[7/11] 测试用户登出(带token)...")
url = f"{API_BASE_URL}/api/auth/logout"
headers = {"Authorization": f"Bearer {token}"}
try:
start_time = time.time()
response = requests.post(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/logout (带token)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/logout (带token)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 8. 登出 - 不带token
print("[8/11] 测试用户登出(不带token)...")
try:
start_time = time.time()
response = requests.post(url, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/logout (不带token)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '认证接口',
'endpoint': '/api/auth/logout (不带token)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 9-11. 并发登录测试
print("[9-11/11] 测试并发登录(3次)...")
url = f"{API_BASE_URL}/api/auth/login"
data = {"username": USERNAME, "password": PASSWORD}
import concurrent.futures
def single_login():
start_time = time.time()
response = requests.post(url, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
return response.status_code, elapsed_time
try:
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
futures = [executor.submit(single_login) for _ in range(3)]
results = [f.result() for f in concurrent.futures.as_completed(futures)]
for i, (status, elapsed) in enumerate(results, 1):
test_results.append({
'module': '认证接口',
'endpoint': f'/api/auth/login (并发{i})',
'method': 'POST',
'status_code': status,
'elapsed_time_ms': f"{elapsed:.2f}",
'success': status == 200,
'error': ''
})
except Exception as e:
for i in range(3):
test_results.append({
'module': '认证接口',
'endpoint': f'/api/auth/login (并发{i+1})',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
api_docs.extend([
{'module': '认证接口', 'endpoint': '/api/auth/login', 'method': 'POST', 'description': '统一登录(支持用户名/手机号)', 'auth': ''},
{'module': '认证接口', 'endpoint': '/api/auth/employee/login', 'method': 'POST', 'description': '员工登录', 'auth': ''},
{'module': '认证接口', 'endpoint': '/api/auth/logout', 'method': 'POST', 'description': '用户登出', 'auth': '可选'},
])
# ============================================================================
# 模块3: 工作台接口测试 (原脚本测试数: 7个)
# ============================================================================
def test_dashboard_apis(token):
"""测试工作台接口 - 概览、最近发布、热门产品"""
if not TEST_MODULES['dashboard']:
return
print_module_header("工作台接口测试", 3, 10)
headers = {"Authorization": f"Bearer {token}"}
# 1-5. 工作台概览 (多次测试获取平均性能)
print("\n[1-5/9] 测试工作台概览(5次)...")
url = f"{API_BASE_URL}/api/dashboard/overview"
for i in range(5):
try:
start_time = time.time()
response = requests.get(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '工作台',
'endpoint': f'/api/dashboard/overview (第{i+1}次)',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '工作台',
'endpoint': f'/api/dashboard/overview (第{i+1}次)',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 6-8. 最近发布 (不同limit参数)
print("[6-8/9] 测试最近发布(不同参数)...")
url = f"{API_BASE_URL}/api/dashboard/recent-publishes"
test_cases = [
{"limit": 5, "desc": "5条记录"},
{"limit": 10, "desc": "10条记录"},
{"limit": 20, "desc": "20条记录"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '工作台',
'endpoint': f'/api/dashboard/recent-publishes ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '工作台',
'endpoint': f'/api/dashboard/recent-publishes ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 9. 热门产品
print("[9/9] 测试热门产品...")
url = f"{API_BASE_URL}/api/dashboard/hot-products"
test_cases = [
{"limit": 4, "desc": "4个产品"},
{"limit": 8, "desc": "8个产品"},
{"limit": 12, "desc": "12个产品"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '工作台',
'endpoint': f'/api/dashboard/hot-products ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '工作台',
'endpoint': f'/api/dashboard/hot-products ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
api_docs.extend([
{'module': '工作台', 'endpoint': '/api/dashboard/overview', 'method': 'GET', 'description': '工作台概览(统计数据)', 'auth': '需要'},
{'module': '工作台', 'endpoint': '/api/dashboard/recent-publishes', 'method': 'GET', 'description': '最近发布(可指定条数)', 'auth': '需要'},
{'module': '工作台', 'endpoint': '/api/dashboard/hot-products', 'method': 'GET', 'description': '热门产品(按发布次数)', 'auth': '需要'},
])
# ============================================================================
# 模块4: 企业接口测试 (原脚本测试数: 15个)
# ============================================================================
def test_enterprise_apis(token):
"""测试企业接口 - 列表、统计、信息、CRUD操作"""
if not TEST_MODULES['enterprise']:
return
print_module_header("企业接口测试", 4, 10)
headers = {"Authorization": f"Bearer {token}"}
# 1-5. 企业列表 (不同查询参数)
print("\n[1-5/17] 测试企业列表(不同参数)...")
url = f"{API_BASE_URL}/api/enterprises/list"
test_cases = [
{"page": 1, "pageSize": 20, "desc": "基本查询"},
{"page": 1, "pageSize": 10, "desc": "每页10条"},
{"page": 1, "pageSize": 20, "keyword": "企业", "desc": "关键词搜索"},
{"page": 1, "pageSize": 20, "status": "active", "desc": "状态筛选"},
{"page": 2, "pageSize": 20, "desc": "第2页"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '企业接口',
'endpoint': f'/api/enterprises/list ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '企业接口',
'endpoint': f'/api/enterprises/list ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 6-10. 企业统计 (多次测试)
print("[6-10/17] 测试企业统计(5次)...")
url = f"{API_BASE_URL}/api/enterprises/stats"
for i in range(5):
try:
start_time = time.time()
response = requests.get(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '企业接口',
'endpoint': f'/api/enterprises/stats (第{i+1}次)',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '企业接口',
'endpoint': f'/api/enterprises/stats (第{i+1}次)',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 11-15. 企业信息 (多次测试)
print("[11-15/17] 测试企业信息(5次)...")
url = f"{API_BASE_URL}/api/enterprises/info"
for i in range(5):
try:
start_time = time.time()
response = requests.get(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '企业接口',
'endpoint': f'/api/enterprises/info (第{i+1}次)',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '企业接口',
'endpoint': f'/api/enterprises/info (第{i+1}次)',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 16. 更新企业信息
print("[16/17] 测试更新企业信息...")
url = f"{API_BASE_URL}/api/enterprises/info"
data = {"short_name": f"测试更新{int(time.time())}", "email": "test@example.com"}
try:
start_time = time.time()
response = requests.put(url, headers=headers, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '企业接口',
'endpoint': '/api/enterprises/info (PUT)',
'method': 'PUT',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '企业接口',
'endpoint': '/api/enterprises/info (PUT)',
'method': 'PUT',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 17. 修改密码
print("[17/17] 测试修改密码...")
url = f"{API_BASE_URL}/api/enterprises/change-password"
data = {"old_password": "wrong", "new_password": "test123"}
try:
start_time = time.time()
response = requests.put(url, headers=headers, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '企业接口',
'endpoint': '/api/enterprises/change-password',
'method': 'PUT',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 400],
'error': ''
})
except Exception as e:
test_results.append({
'module': '企业接口',
'endpoint': '/api/enterprises/change-password',
'method': 'PUT',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
api_docs.extend([
{'module': '企业接口', 'endpoint': '/api/enterprises/list', 'method': 'GET', 'description': '企业列表(支持分页、搜索、筛选)', 'auth': '需要'},
{'module': '企业接口', 'endpoint': '/api/enterprises/stats', 'method': 'GET', 'description': '企业统计(总数、激活数等)', 'auth': '需要'},
{'module': '企业接口', 'endpoint': '/api/enterprises/info', 'method': 'GET', 'description': '企业信息', 'auth': '需要'},
{'module': '企业接口', 'endpoint': '/api/enterprises/info', 'method': 'PUT', 'description': '更新企业信息', 'auth': '需要'},
{'module': '企业接口', 'endpoint': '/api/enterprises/change-password', 'method': 'PUT', 'description': '修改密码', 'auth': '需要'},
])
# ============================================================================
# 模块5: 图片接口测试 (原脚本测试数: 17个)
# ============================================================================
def test_image_apis(token):
"""测试图片接口 - 图片、标签、类型管理"""
if not TEST_MODULES['image']:
return
print_module_header("图片接口测试", 5, 10)
headers = {"Authorization": f"Bearer {token}"}
# 1-2. 图片列表
print("\n[1-2/17] 测试图片列表(不同参数)...")
url = f"{API_BASE_URL}/api/images/list"
test_cases = [
{"page": 1, "pageSize": 20, "desc": "第1页"},
{"page": 1, "pageSize": 10, "desc": "每页10条"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '图片接口',
'endpoint': f'/api/images/list ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '图片接口',
'endpoint': f'/api/images/list ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 3. 图片仪表盘
print("[3/17] 测试图片仪表盘...")
url = f"{API_BASE_URL}/api/images/list_dashboard"
try:
start_time = time.time()
response = requests.get(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '图片接口',
'endpoint': '/api/images/list_dashboard',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '图片接口',
'endpoint': '/api/images/list_dashboard',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 4. 上传图片
print("[4/17] 测试上传图片...")
url = f"{API_BASE_URL}/api/images/upload"
try:
img = Image.new('RGB', (100, 100))
img_bytes = io.BytesIO()
img.save(img_bytes, format='PNG')
img_bytes.seek(0)
files = {'image': ('test.png', img_bytes, 'image/png')}
data = {'image_name': '测试图片', 'image_type_name': '测试类型', 'tag_keywords': '测试,性能'}
start_time = time.time()
response = requests.post(url, headers=headers, files=files, data=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '图片接口',
'endpoint': '/api/images/upload',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 400],
'error': ''
})
except Exception as e:
test_results.append({
'module': '图片接口',
'endpoint': '/api/images/upload',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 5. 删除图片
print("[5/17] 测试删除图片...")
url = f"{API_BASE_URL}/api/images/999999"
try:
start_time = time.time()
response = requests.delete(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '图片接口',
'endpoint': '/api/images/<id>',
'method': 'DELETE',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 404],
'error': ''
})
except Exception as e:
test_results.append({
'module': '图片接口',
'endpoint': '/api/images/<id>',
'method': 'DELETE',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 6. 标签名称列表
print("[6/17] 测试标签名称列表...")
url = f"{API_BASE_URL}/api/images/tags/names/list"
try:
start_time = time.time()
response = requests.get(url, headers=headers, params={"page": 1, "pageSize": 20}, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '图片接口',
'endpoint': '/api/images/tags/names/list',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '图片接口',
'endpoint': '/api/images/tags/names/list',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 7. 创建标签名称
print("[7/17] 测试创建标签名称...")
url = f"{API_BASE_URL}/api/images/tags/names/create"
data = {"tag_name": f"测试标签{int(time.time())}", "description": "测试"}
try:
start_time = time.time()
response = requests.post(url, headers=headers, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '图片接口',
'endpoint': '/api/images/tags/names/create',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 400],
'error': ''
})
except Exception as e:
test_results.append({
'module': '图片接口',
'endpoint': '/api/images/tags/names/create',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 8-11. 标签名称CRUD操作
print("[8-11/17] 测试标签名称CRUD...")
endpoints = [
('/api/images/tags/names/999999', 'PUT', '更新标签名称'),
('/api/images/tags/names/999999', 'DELETE', '删除标签名称'),
('/api/images/tags/relations/list', 'GET', '标签关系列表'),
('/api/images/types/list', 'GET', '图片类型列表'),
]
for endpoint, method, desc in endpoints:
url = f"{API_BASE_URL}{endpoint}"
try:
start_time = time.time()
if method == 'GET':
response = requests.get(url, headers=headers, params={"page": 1, "pageSize": 20}, timeout=30)
elif method == 'PUT':
response = requests.put(url, headers=headers, json={"description": "更新"}, timeout=30)
else:
response = requests.delete(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '图片接口',
'endpoint': f'{endpoint} ({desc})',
'method': method,
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 404],
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '图片接口',
'endpoint': f'{endpoint} ({desc})',
'method': method,
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 12-17. 图片类型和标签管理
print("[12-17/17] 测试类型和标签管理...")
test_cases = [
('/api/images/types/create', 'POST', {"type_name": f"测试类型{int(time.time())}"}, '创建类型'),
('/api/images/types/999999', 'PUT', {"type_name": "更新类型"}, '更新类型'),
('/api/images/types/999999', 'DELETE', None, '删除类型'),
('/api/images/tags/list', 'GET', None, '标签列表'),
('/api/images/tags/create', 'POST', {"image_id": 1, "tag_id": 1}, '创建标签'),
('/api/images/tags/999999', 'DELETE', None, '删除标签'),
]
for endpoint, method, data, desc in test_cases:
url = f"{API_BASE_URL}{endpoint}"
try:
start_time = time.time()
if method == 'GET':
response = requests.get(url, headers=headers, params={"page": 1, "pageSize": 20}, timeout=30)
elif method == 'POST':
response = requests.post(url, headers=headers, json=data, timeout=30)
elif method == 'PUT':
response = requests.put(url, headers=headers, json=data, timeout=30)
else:
response = requests.delete(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '图片接口',
'endpoint': f'{endpoint} ({desc})',
'method': method,
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 400, 404, 409],
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '图片接口',
'endpoint': f'{endpoint} ({desc})',
'method': method,
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
api_docs.extend([
{'module': '图片接口', 'endpoint': '/api/images/list', 'method': 'GET', 'description': '图片列表', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/list_dashboard', 'method': 'GET', 'description': '图片仪表盘', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/upload', 'method': 'POST', 'description': '上传图片', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/<id>', 'method': 'DELETE', 'description': '删除图片', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/tags/names/list', 'method': 'GET', 'description': '标签名称列表', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/tags/names/create', 'method': 'POST', 'description': '创建标签名称', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/tags/names/<id>', 'method': 'PUT', 'description': '更新标签名称', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/tags/names/<id>', 'method': 'DELETE', 'description': '删除标签名称', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/tags/relations/list', 'method': 'GET', 'description': '标签关系列表', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/types/list', 'method': 'GET', 'description': '图片类型列表', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/types/create', 'method': 'POST', 'description': '创建类型', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/types/<id>', 'method': 'PUT', 'description': '更新类型', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/types/<id>', 'method': 'DELETE', 'description': '删除类型', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/tags/list', 'method': 'GET', 'description': '标签列表', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/tags/create', 'method': 'POST', 'description': '创建标签', 'auth': '需要'},
{'module': '图片接口', 'endpoint': '/api/images/tags/<id>', 'method': 'DELETE', 'description': '删除标签', 'auth': '需要'},
])
# ============================================================================
# 模块6: 日志接口测试 (原脚本测试数: 7个)
# ============================================================================
def test_log_apis(token):
"""测试日志接口 - 操作日志、文件日志"""
if not TEST_MODULES['log']:
return
print_module_header("日志接口测试", 6, 10)
headers = {"Authorization": f"Bearer {token}"}
# 1-3. 获取操作日志 (不同参数)
print("\n[1-3/7] 测试获取操作日志...")
url = f"{API_BASE_URL}/api/log/logs"
test_cases = [
{"page": 1, "size": 10, "desc": "第1页10条"},
{"page": 1, "size": 20, "desc": "第1页20条"},
{"page": 2, "size": 10, "desc": "第2页10条"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '日志接口',
'endpoint': f'/api/log/logs ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 500],
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '日志接口',
'endpoint': f'/api/log/logs ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 4. 日志文件列表
print("[4/7] 测试日志文件列表...")
url = f"{API_BASE_URL}/api/log/logs/files"
try:
start_time = time.time()
response = requests.get(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '日志接口',
'endpoint': '/api/log/logs/files',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '日志接口',
'endpoint': '/api/log/logs/files',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 5-7. 文件日志内容 (不同类型和行数)
print("[5-7/7] 测试文件日志内容...")
url = f"{API_BASE_URL}/api/log/logs/file"
test_cases = [
{"type": "article", "lines": 50, "desc": "article日志50行"},
{"type": "error", "lines": 50, "desc": "error日志50行"},
{"type": "article", "lines": 100, "desc": "article日志100行"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '日志接口',
'endpoint': f'/api/log/logs/file ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 404],
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '日志接口',
'endpoint': f'/api/log/logs/file ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
api_docs.extend([
{'module': '日志接口', 'endpoint': '/api/log/logs', 'method': 'GET', 'description': '获取操作日志(分页)', 'auth': '需要'},
{'module': '日志接口', 'endpoint': '/api/log/logs/files', 'method': 'GET', 'description': '日志文件列表', 'auth': '需要'},
{'module': '日志接口', 'endpoint': '/api/log/logs/file', 'method': 'GET', 'description': '文件日志内容', 'auth': '需要'},
])
# ============================================================================
# 模块7: 文章接口测试 (原脚本测试数: 10个)
# ============================================================================
def test_article_apis(token):
"""测试文章接口 - 列表、详情、发布"""
if not TEST_MODULES['article']:
return
print_module_header("文章接口测试", 7, 10)
headers = {"Authorization": f"Bearer {token}"}
# 1-3. 文章列表 (不同参数)
print("\n[1-3/10] 测试文章列表...")
url = f"{API_BASE_URL}/api/articles/list"
test_cases = [
{"page": 1, "pageSize": 20, "desc": "基本查询"},
{"page": 1, "pageSize": 10, "keyword": "文章", "desc": "关键词搜索"},
{"page": 2, "pageSize": 20, "desc": "第2页"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '文章接口',
'endpoint': f'/api/articles/list ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '文章接口',
'endpoint': f'/api/articles/list ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 4. 文章仪表盘
print("[4/10] 测试文章仪表盘...")
url = f"{API_BASE_URL}/api/articles/list_dashboard"
try:
start_time = time.time()
response = requests.get(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '文章接口',
'endpoint': '/api/articles/list_dashboard',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '文章接口',
'endpoint': '/api/articles/list_dashboard',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 5. 生成文章
print("[5/10] 测试生成文章...")
url = f"{API_BASE_URL}/api/articles/generate"
data = {"product_id": 1, "prompt_workflow_id": 1, "topics": ["测试主题1", "测试主题2"], "count": 2}
try:
start_time = time.time()
response = requests.post(url, headers=headers, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '文章接口',
'endpoint': '/api/articles/generate',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 400],
'error': ''
})
except Exception as e:
test_results.append({
'module': '文章接口',
'endpoint': '/api/articles/generate',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 6-10. 文章详情和更新(如果有文章)
print("[6-10/10] 测试文章详情和操作...")
list_response = requests.get(f"{API_BASE_URL}/api/articles/list", headers=headers,
params={"page": 1, "pageSize": 1}, timeout=30)
if list_response.status_code == 200:
articles = list_response.json().get('data', {}).get('list', [])
if articles:
article_id = articles[0]['id']
# 文章详情
url = f"{API_BASE_URL}/api/articles/{article_id}"
try:
start_time = time.time()
response = requests.get(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '文章接口',
'endpoint': f'/api/articles/{article_id}',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '文章接口',
'endpoint': f'/api/articles/{article_id}',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 更新文章
data = {"title": f"测试更新标题_{int(time.time())}", "status": "draft"}
try:
start_time = time.time()
response = requests.put(url, headers=headers, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '文章接口',
'endpoint': f'/api/articles/{article_id} (PUT)',
'method': 'PUT',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '文章接口',
'endpoint': f'/api/articles/{article_id} (PUT)',
'method': 'PUT',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 批量发布测试
print(" 测试批量发布接口...")
endpoints = [
('/api/articles/batch-published-account-cycle', {"article_ids": [1, 2], "author_ids": [1, 2]}, '账号循环'),
('/api/articles/batch-published-review', {"article_ids": [1, 2], "author_id": 1}, '指定作者'),
]
for endpoint, data, desc in endpoints:
url = f"{API_BASE_URL}{endpoint}"
try:
start_time = time.time()
response = requests.post(url, headers=headers, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '文章接口',
'endpoint': f'{endpoint} ({desc})',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 400],
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '文章接口',
'endpoint': f'{endpoint} ({desc})',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
api_docs.extend([
{'module': '文章接口', 'endpoint': '/api/articles/list', 'method': 'GET', 'description': '文章列表', 'auth': '需要'},
{'module': '文章接口', 'endpoint': '/api/articles/list_dashboard', 'method': 'GET', 'description': '文章仪表盘', 'auth': '需要'},
{'module': '文章接口', 'endpoint': '/api/articles/generate', 'method': 'POST', 'description': '生成文章', 'auth': '需要'},
{'module': '文章接口', 'endpoint': '/api/articles/<id>', 'method': 'GET', 'description': '文章详情', 'auth': '需要'},
{'module': '文章接口', 'endpoint': '/api/articles/<id>', 'method': 'PUT', 'description': '更新文章', 'auth': '需要'},
{'module': '文章接口', 'endpoint': '/api/articles/batch-published-account-cycle', 'method': 'POST', 'description': '批量发布(账号循环)', 'auth': '需要'},
{'module': '文章接口', 'endpoint': '/api/articles/batch-published-review', 'method': 'POST', 'description': '批量发布(指定作者)', 'auth': '需要'},
])
# ============================================================================
# 模块8: 员工接口测试 (原脚本测试数: 8个)
# ============================================================================
def test_employee_apis(token):
"""测试员工接口 - 列表、统计、CRUD"""
if not TEST_MODULES['employee']:
return
print_module_header("员工接口测试", 8, 10)
headers = {"Authorization": f"Bearer {token}"}
# 1-5. 员工列表 (不同参数)
print("\n[1-5/8] 测试员工列表(不同参数)...")
url = f"{API_BASE_URL}/api/employees/list"
test_cases = [
{"page": 1, "pageSize": 20, "desc": "基本查询"},
{"page": 1, "pageSize": 10, "desc": "每页10条"},
{"page": 1, "pageSize": 20, "keyword": "员工", "desc": "关键词搜索"},
{"page": 1, "pageSize": 20, "status": "active", "desc": "状态筛选"},
{"page": 2, "pageSize": 20, "desc": "第2页"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '员工接口',
'endpoint': f'/api/employees/list ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '员工接口',
'endpoint': f'/api/employees/list ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 6. 员工统计
print("[6/8] 测试员工统计...")
url = f"{API_BASE_URL}/api/employees/stats"
try:
start_time = time.time()
response = requests.get(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '员工接口',
'endpoint': '/api/employees/stats',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '员工接口',
'endpoint': '/api/employees/stats',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 7. 添加员工
print("[7/8] 测试添加员工...")
url = f"{API_BASE_URL}/api/employees/add"
timestamp = int(time.time())
data = {
"name": f"测试员工{timestamp}",
"phone": f"1382{timestamp % 10000000:07d}",
"password": "test123456",
"role": "employee",
"department": "测试部门"
}
try:
start_time = time.time()
response = requests.post(url, headers=headers, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '员工接口',
'endpoint': '/api/employees/add',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 400],
'error': ''
})
except Exception as e:
test_results.append({
'module': '员工接口',
'endpoint': '/api/employees/add',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 8. 删除员工
print("[8/8] 测试删除员工...")
url = f"{API_BASE_URL}/api/employees/999999"
try:
start_time = time.time()
response = requests.delete(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '员工接口',
'endpoint': '/api/employees/<id>',
'method': 'DELETE',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 404],
'error': ''
})
except Exception as e:
test_results.append({
'module': '员工接口',
'endpoint': '/api/employees/<id>',
'method': 'DELETE',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
api_docs.extend([
{'module': '员工接口', 'endpoint': '/api/employees/list', 'method': 'GET', 'description': '员工列表(分页、搜索)', 'auth': '需要'},
{'module': '员工接口', 'endpoint': '/api/employees/stats', 'method': 'GET', 'description': '员工统计', 'auth': '需要'},
{'module': '员工接口', 'endpoint': '/api/employees/add', 'method': 'POST', 'description': '添加员工', 'auth': '需要'},
{'module': '员工接口', 'endpoint': '/api/employees/<id>', 'method': 'DELETE', 'description': '删除员工', 'auth': '需要'},
])
# ============================================================================
# 模块9: 作者接口测试 (原脚本测试数: 20个)
# ============================================================================
def test_author_apis(token):
"""测试作者接口 - 列表、搜索、CRUD"""
if not TEST_MODULES['author']:
return
print_module_header("作者接口测试", 9, 10)
headers = {"Authorization": f"Bearer {token}"}
# 1-3. 作者列表 (不同参数)
print("\n[1-3/12] 测试作者列表...")
url = f"{API_BASE_URL}/api/authors"
test_cases = [
{"page": 1, "size": 10, "desc": "第1页"},
{"page": 1, "size": 5, "desc": "每页5条"},
{"page": 1, "size": 10, "search": "医生", "desc": "搜索关键词"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '作者接口',
'endpoint': f'/api/authors ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '作者接口',
'endpoint': f'/api/authors ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 4. 作者列表(用户关联)
print("[4/12] 测试作者列表(用户关联)...")
url = f"{API_BASE_URL}/api/authors/list"
try:
start_time = time.time()
response = requests.get(url, headers=headers, params={"page": 1, "size": 10}, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '作者接口',
'endpoint': '/api/authors/list',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '作者接口',
'endpoint': '/api/authors/list',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 5-6. 作者详细列表
print("[5-6/12] 测试作者详细列表...")
url = f"{API_BASE_URL}/api/authors/detail_list"
test_cases = [
{"page": 1, "size": 10, "desc": "基本查询"},
{"page": 1, "size": 20, "search": "医生", "desc": "搜索查询"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '作者接口',
'endpoint': f'/api/authors/detail_list ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '作者接口',
'endpoint': f'/api/authors/detail_list ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 7. 科室列表
print("[7/12] 测试科室列表...")
url = f"{API_BASE_URL}/api/authors/departments"
try:
start_time = time.time()
response = requests.get(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '作者接口',
'endpoint': '/api/authors/departments',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '作者接口',
'endpoint': '/api/authors/departments',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 8-9. 搜索作者
print("[8-9/12] 测试搜索作者...")
url = f"{API_BASE_URL}/api/authors/search"
test_cases = [
{"keyword": "医生", "limit": 10, "desc": "搜索医生"},
{"keyword": "科室", "limit": 5, "desc": "搜索科室"},
]
for i, params in enumerate(test_cases, 1):
desc = params.pop('desc')
try:
start_time = time.time()
response = requests.get(url, headers=headers, params=params, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '作者接口',
'endpoint': f'/api/authors/search ({desc})',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '作者接口',
'endpoint': f'/api/authors/search ({desc})',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 10-12. 作者CRUD操作
print("[10-12/12] 测试作者CRUD...")
# 创建作者
url = f"{API_BASE_URL}/api/authors"
timestamp = int(time.time())
data = {
"author_name": f"测试医生{timestamp}",
"app_id": f"test_app_{timestamp}",
"app_token": f"test_token_{timestamp}",
"department_name": "测试科室",
"title": "主任医师",
"hospital": "测试医院",
"channel": 1
}
try:
start_time = time.time()
response = requests.post(url, headers=headers, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '作者接口',
'endpoint': '/api/authors (POST)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 201, 400],
'error': ''
})
except Exception as e:
test_results.append({
'module': '作者接口',
'endpoint': '/api/authors (POST)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 更新和删除
for endpoint, method, desc in [
('/api/authors/999999', 'PUT', '更新作者'),
('/api/authors/999999', 'DELETE', '删除作者'),
]:
url = f"{API_BASE_URL}{endpoint}"
try:
start_time = time.time()
if method == 'PUT':
response = requests.put(url, headers=headers, json={"author_name": "更新测试"}, timeout=30)
else:
response = requests.delete(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '作者接口',
'endpoint': f'{endpoint} ({desc})',
'method': method,
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 404],
'error': ''
})
time.sleep(0.1)
except Exception as e:
test_results.append({
'module': '作者接口',
'endpoint': f'{endpoint} ({desc})',
'method': method,
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
api_docs.extend([
{'module': '作者接口', 'endpoint': '/api/authors', 'method': 'GET', 'description': '作者列表(按科室分组)', 'auth': '需要'},
{'module': '作者接口', 'endpoint': '/api/authors', 'method': 'POST', 'description': '创建作者', 'auth': '需要'},
{'module': '作者接口', 'endpoint': '/api/authors/<id>', 'method': 'PUT', 'description': '更新作者', 'auth': '需要'},
{'module': '作者接口', 'endpoint': '/api/authors/<id>', 'method': 'DELETE', 'description': '删除作者', 'auth': '需要'},
{'module': '作者接口', 'endpoint': '/api/authors/list', 'method': 'GET', 'description': '作者列表(用户关联)', 'auth': '需要'},
{'module': '作者接口', 'endpoint': '/api/authors/detail_list', 'method': 'GET', 'description': '作者详细列表', 'auth': '需要'},
{'module': '作者接口', 'endpoint': '/api/authors/departments', 'method': 'GET', 'description': '科室列表', 'auth': '需要'},
{'module': '作者接口', 'endpoint': '/api/authors/search', 'method': 'GET', 'description': '搜索作者', 'auth': '需要'},
])
# ============================================================================
# 模块10: 搜索服务接口测试 (原脚本测试数: 6个)
# ============================================================================
def test_search_apis(token):
"""测试搜索服务接口 - 独立服务8321端口"""
if not TEST_MODULES['search']:
return
print_module_header("搜索服务接口测试", 10, 10)
print("注意: 搜索服务使用独立端口 8321")
headers = {"Authorization": f"Bearer {token}"}
# 1. 健康检查
print("\n[1/6] 测试健康检查...")
url = f"{SEARCH_API_BASE_URL}/health"
try:
start_time = time.time()
response = requests.get(url, timeout=5)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '搜索服务',
'endpoint': '/health',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '搜索服务',
'endpoint': '/health',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 2. 查询日志
print("[2/6] 测试查询日志...")
url = f"{SEARCH_API_BASE_URL}/api/search-service/logs"
try:
start_time = time.time()
response = requests.get(url, headers=headers, params={"page": 1, "size": 10}, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '搜索服务',
'endpoint': '/api/search-service/logs',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 500],
'error': ''
})
except Exception as e:
test_results.append({
'module': '搜索服务',
'endpoint': '/api/search-service/logs',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 3. 日志文件列表
print("[3/6] 测试日志文件列表...")
url = f"{SEARCH_API_BASE_URL}/api/search-service/logs/files"
try:
start_time = time.time()
response = requests.get(url, headers=headers, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '搜索服务',
'endpoint': '/api/search-service/logs/files',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code == 200,
'error': ''
})
except Exception as e:
test_results.append({
'module': '搜索服务',
'endpoint': '/api/search-service/logs/files',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 4. 文件日志内容
print("[4/6] 测试文件日志内容...")
url = f"{SEARCH_API_BASE_URL}/api/search-service/logs/file"
try:
start_time = time.time()
response = requests.get(url, headers=headers, params={"type": "article", "lines": 50}, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '搜索服务',
'endpoint': '/api/search-service/logs/file',
'method': 'GET',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 404],
'error': ''
})
except Exception as e:
test_results.append({
'module': '搜索服务',
'endpoint': '/api/search-service/logs/file',
'method': 'GET',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 5. 生成文章
print("[5/6] 测试生成文章...")
url = f"{SEARCH_API_BASE_URL}/api/search-service/generate_article"
data = {"query": "测试查询", "max_results": 5}
try:
start_time = time.time()
response = requests.post(url, headers=headers, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '搜索服务',
'endpoint': '/api/search-service/generate_article',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 400],
'error': ''
})
except Exception as e:
test_results.append({
'module': '搜索服务',
'endpoint': '/api/search-service/generate_article',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 6. 关键词搜索
print("[6/6] 测试关键词搜索...")
url = f"{SEARCH_API_BASE_URL}/api/search-service/search"
data = {"keyword": "测试", "limit": 10}
try:
start_time = time.time()
response = requests.post(url, headers=headers, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
test_results.append({
'module': '搜索服务',
'endpoint': '/api/search-service/search',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': response.status_code in [200, 400],
'error': ''
})
except Exception as e:
test_results.append({
'module': '搜索服务',
'endpoint': '/api/search-service/search',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
api_docs.extend([
{'module': '搜索服务', 'endpoint': '/health', 'method': 'GET', 'description': '健康检查', 'auth': '不需要'},
{'module': '搜索服务', 'endpoint': '/api/search-service/logs', 'method': 'GET', 'description': '查询日志', 'auth': '需要'},
{'module': '搜索服务', 'endpoint': '/api/search-service/logs/files', 'method': 'GET', 'description': '日志文件列表', 'auth': '需要'},
{'module': '搜索服务', 'endpoint': '/api/search-service/logs/file', 'method': 'GET', 'description': '文件日志内容', 'auth': '需要'},
{'module': '搜索服务', 'endpoint': '/api/search-service/generate_article', 'method': 'POST', 'description': '生成文章', 'auth': '需要'},
{'module': '搜索服务', 'endpoint': '/api/search-service/search', 'method': 'POST', 'description': '关键词搜索', 'auth': '需要'},
])
# ============================================================================
# 结果保存和输出
# ============================================================================
def save_to_csv():
"""保存测试结果到CSV文件"""
timestamp = datetime.now().strftime('%Y%m%d')
filename = f'整体后端接口性能测试_{timestamp}.csv'
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=[
'module', 'endpoint', 'method', 'status_code', 'elapsed_time_ms', 'success', 'error'
])
writer.writeheader()
writer.writerows(test_results)
print(f"\n✓ 性能测试结果已保存到: {filename}")
return filename
def save_api_docs():
"""保存接口文档到CSV文件"""
timestamp = datetime.now().strftime('%Y%m%d')
filename = f'整体后端接口文档_{timestamp}.csv'
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=[
'module', 'endpoint', 'method', 'description', 'auth'
])
writer.writeheader()
writer.writerows(api_docs)
print(f"✓ 接口文档已保存到: {filename}")
return filename
def generate_markdown_report():
"""生成Markdown格式的综合数据报表"""
from collections import defaultdict
timestamp = datetime.now().strftime('%Y%m%d')
filename = f'整体后端接口测试报表_{timestamp}.md'
# 总体统计
total = len(test_results)
success = sum(1 for r in test_results if r['success'])
failed = total - success
times = [float(r['elapsed_time_ms']) for r in test_results if r['elapsed_time_ms'] != '0']
avg_time = sum(times) / len(times) if times else 0
max_time = max(times) if times else 0
min_time = min(times) if times else 0
# 找出最快和最慢的接口
max_item = max(test_results, key=lambda x: float(x['elapsed_time_ms']) if x['elapsed_time_ms'] != '0' else 0)
min_item = min([r for r in test_results if r['elapsed_time_ms'] != '0'],
key=lambda x: float(x['elapsed_time_ms'])) if times else None
# 按模块统计
modules = {}
for r in test_results:
module = r['module']
if module not in modules:
modules[module] = {
'total': 0,
'success': 0,
'times': [],
'endpoints': [],
'errors': []
}
modules[module]['total'] += 1
if r['success']:
modules[module]['success'] += 1
else:
modules[module]['errors'].append(r['endpoint'])
if r['elapsed_time_ms'] != '0':
modules[module]['times'].append(float(r['elapsed_time_ms']))
modules[module]['endpoints'].append((r['endpoint'], float(r['elapsed_time_ms'])))
# HTTP方法统计
methods = defaultdict(lambda: {'total': 0, 'success': 0})
for r in test_results:
method = r['method']
methods[method]['total'] += 1
if r['success']:
methods[method]['success'] += 1
# 性能分布
fast = sum(1 for t in times if t < 100)
normal = sum(1 for t in times if 100 <= t < 500)
slow = sum(1 for t in times if 500 <= t < 1000)
very_slow = sum(1 for t in times if t >= 1000)
# 状态码分布
status_codes = defaultdict(int)
for r in test_results:
status_codes[r['status_code']] += 1
# 接口文档统计
doc_modules = defaultdict(int)
doc_methods = defaultdict(int)
auth_required = sum(1 for d in api_docs if d['auth'] == '需要')
for doc in api_docs:
doc_modules[doc['module']] += 1
doc_methods[doc['method']] += 1
# 开始写入Markdown文件
with open(filename, 'w', encoding='utf-8') as f:
# 标题和概览
f.write("# 整体后端接口性能测试报表\n\n")
f.write(f"**生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
f.write("---\n\n")
# 总体统计
f.write("## 📈 总体测试统计\n\n")
f.write("| 指标 | 数值 |\n")
f.write("|------|------|\n")
f.write(f"| 测试总数 | {total} 个 |\n")
f.write(f"| 成功数量 | {success} 个 ✓ |\n")
f.write(f"| 失败数量 | {failed} 个 ✗ |\n")
f.write(f"| **成功率** | **{success/total*100:.2f}%** |\n")
f.write(f"| 平均耗时 | {avg_time:.2f}ms |\n")
f.write(f"| 最大耗时 | {max_time:.2f}ms |\n")
f.write(f"| 最小耗时 | {min_time:.2f}ms |\n\n")
if max_item:
f.write("**最慢接口**:\n")
f.write(f"- `{max_item['endpoint']}` ({max_item['module']}) - {max_item['elapsed_time_ms']}ms\n\n")
if min_item:
f.write("**最快接口**:\n")
f.write(f"- `{min_item['endpoint']}` ({min_item['module']}) - {min_item['elapsed_time_ms']}ms\n\n")
f.write("---\n\n")
# 各模块性能分析
f.write("## 📊 各模块性能分析\n\n")
sorted_modules = sorted(modules.items(),
key=lambda x: (x[1]['success']/x[1]['total'] if x[1]['total'] > 0 else 0),
reverse=True)
f.write("| 模块 | 测试数 | 成功 | 失败 | 成功率 | 平均耗时 | 最大耗时 | 最小耗时 | 状态 |\n")
f.write("|------|--------|------|------|--------|----------|----------|----------|------|\n")
for module, stats in sorted_modules:
success_rate = (stats['success'] / stats['total'] * 100) if stats['total'] > 0 else 0
avg_time = (sum(stats['times']) / len(stats['times'])) if stats['times'] else 0
max_time = max(stats['times']) if stats['times'] else 0
min_time = min(stats['times']) if stats['times'] else 0
if success_rate >= 90:
status = "🟢 优秀"
elif success_rate >= 70:
status = "🟡 良好"
elif success_rate >= 50:
status = "🟠 一般"
else:
status = "🔴 需优化"
f.write(f"| {module} | {stats['total']} | {stats['success']} | {stats['total']-stats['success']} | "
f"{success_rate:.1f}% | {avg_time:.2f}ms | {max_time:.2f}ms | {min_time:.2f}ms | {status} |\n")
f.write("\n")
# 失败接口详情
f.write("### ⚠️ 失败接口详情\n\n")
has_errors = False
for module, stats in sorted_modules:
if stats['errors']:
has_errors = True
f.write(f"**{module}** ({len(stats['errors'])}个失败): \n")
for err_endpoint in stats['errors']:
f.write(f"- `{err_endpoint}`\n")
f.write("\n")
if not has_errors:
f.write("✅ 所有接口测试通过!\n\n")
f.write("---\n\n")
# HTTP方法分布
f.write("## 🔧 HTTP方法分布\n\n")
f.write("| 方法 | 总数 | 成功 | 失败 | 成功率 |\n")
f.write("|------|------|------|------|--------|\n")
for method, stats in sorted(methods.items()):
success_rate = (stats['success'] / stats['total'] * 100) if stats['total'] > 0 else 0
f.write(f"| {method} | {stats['total']} | {stats['success']} | "
f"{stats['total']-stats['success']} | {success_rate:.1f}% |\n")
f.write("\n---\n\n")
# 性能分布
f.write("## ⚡ 性能分布分析\n\n")
f.write("| 性能等级 | 数量 | 占比 |\n")
f.write("|----------|------|------|\n")
f.write(f"| 🚀 极快 (<100ms) | {fast} | {fast/len(times)*100:.1f}% |\n")
f.write(f"| ✅ 正常 (100-500ms) | {normal} | {normal/len(times)*100:.1f}% |\n")
f.write(f"| ⚠️ 较慢 (500-1000ms) | {slow} | {slow/len(times)*100:.1f}% |\n")
f.write(f"| 🐌 很慢 (>1000ms) | {very_slow} | {very_slow/len(times)*100:.1f}% |\n")
f.write("\n")
# 性能分布图(文本版)
f.write("### 性能分布可视化\n\n")
f.write("```\n")
max_bar_len = 50
if times:
fast_bar = '' * int((fast/len(times)) * max_bar_len)
normal_bar = '' * int((normal/len(times)) * max_bar_len)
slow_bar = '' * int((slow/len(times)) * max_bar_len)
very_slow_bar = '' * int((very_slow/len(times)) * max_bar_len)
f.write(f"极快 (<100ms): {fast_bar} {fast}\n")
f.write(f"正常 (100-500ms): {normal_bar} {normal}\n")
f.write(f"较慢 (500-1000ms):{slow_bar} {slow}\n")
f.write(f"很慢 (>1000ms): {very_slow_bar} {very_slow}\n")
f.write("```\n\n")
f.write("---\n\n")
# HTTP状态码分布
f.write("## 📋 HTTP状态码分布\n\n")
f.write("| 状态码 | 数量 | 占比 | 说明 |\n")
f.write("|--------|------|------|------|\n")
for code, count in sorted(status_codes.items()):
percentage = (count / total * 100)
if code == 200:
desc = "✅ 成功"
elif code >= 500:
desc = "❌ 服务器错误"
elif code >= 400:
desc = "⚠️ 客户端错误"
elif code == 0:
desc = "❌ 请求失败"
else:
desc = " 其他"
f.write(f"| {code} | {count} | {percentage:.1f}% | {desc} |\n")
f.write("\n---\n\n")
# 接口文档统计
f.write("## 📚 接口文档统计\n\n")
f.write(f"**已记录接口总数**: {len(api_docs)}\n")
f.write(f"**需要认证**: {auth_required} 个 ({auth_required/len(api_docs)*100:.1f}%)\n\n")
f.write("### 按模块分类\n\n")
f.write("| 模块 | 接口数 |\n")
f.write("|------|--------|\n")
for module, count in sorted(doc_modules.items(), key=lambda x: x[1], reverse=True):
f.write(f"| {module} | {count} |\n")
f.write("\n")
f.write("### 按方法分类\n\n")
f.write("| 方法 | 接口数 |\n")
f.write("|------|--------|\n")
for method, count in sorted(doc_methods.items()):
f.write(f"| {method} | {count} |\n")
f.write("\n")
f.write("---\n\n")
# 优化建议
f.write("## 💡 优化建议\n\n")
suggestions = []
# 检查失败率高的模块
for module, stats in modules.items():
success_rate = (stats['success'] / stats['total'] * 100) if stats['total'] > 0 else 0
if success_rate < 70:
suggestions.append(f"🔴 **{module}** 模块成功率仅 {success_rate:.1f}%,建议优先排查认证、参数和数据库连接问题")
# 检查慢接口
slow_endpoints = [(r['module'], r['endpoint'], float(r['elapsed_time_ms']))
for r in test_results if r['elapsed_time_ms'] != '0' and float(r['elapsed_time_ms']) > 500]
if slow_endpoints:
slow_endpoints.sort(key=lambda x: x[2], reverse=True)
suggestions.append(f"⚠️ 发现 {len(slow_endpoints)} 个耗时超过500ms的接口建议添加缓存或优化查询")
suggestions.append(" 慢接口TOP 3:")
for module, endpoint, time in slow_endpoints[:3]:
suggestions.append(f" - `{endpoint}` ({module}) - {time:.2f}ms")
# 检查错误率
if failed > 0:
error_rate = failed / total * 100
if error_rate > 20:
suggestions.append(f"❌ 总体错误率达到 {error_rate:.1f}%,建议进行全面的接口测试和修复")
if suggestions:
for suggestion in suggestions:
f.write(f"{suggestion}\n")
else:
f.write("✅ 所有接口性能良好,无需特别优化\n")
f.write("\n---\n\n")
# 测试配置信息
f.write("## ⚙️ 测试配置\n\n")
f.write(f"- **主服务地址**: `{API_BASE_URL}`\n")
f.write(f"- **搜索服务地址**: `{SEARCH_API_BASE_URL}`\n")
f.write(f"- **测试账号**: `{USERNAME}`\n")
enabled_modules = [name for name, enabled in TEST_MODULES.items() if enabled]
disabled_modules = [name for name, enabled in TEST_MODULES.items() if not enabled]
f.write(f"- **启用模块** ({len(enabled_modules)}个): {', '.join(enabled_modules)}\n")
if disabled_modules:
f.write(f"- **禁用模块** ({len(disabled_modules)}个): {', '.join(disabled_modules)}\n")
f.write("\n---\n\n")
f.write("*报表由整体后端接口性能测试工具自动生成*\n")
print(f"\n✅ Markdown报表已生成: {filename}")
return filename
def generate_data_report():
"""生成综合数据报表"""
from collections import defaultdict
print("\n" + ""*80)
print("📊 综合数据报表")
print(""*80)
# 总体统计
total = len(test_results)
success = sum(1 for r in test_results if r['success'])
failed = total - success
times = [float(r['elapsed_time_ms']) for r in test_results if r['elapsed_time_ms'] != '0']
avg_time = sum(times) / len(times) if times else 0
max_time = max(times) if times else 0
min_time = min(times) if times else 0
# 找出最快和最慢的接口
max_item = min(test_results, key=lambda x: float(x['elapsed_time_ms']) if x['elapsed_time_ms'] != '0' else float('inf'))
min_item = max(test_results, key=lambda x: float(x['elapsed_time_ms']) if x['elapsed_time_ms'] != '0' else 0)
print("\n" + "="*80)
print("📈 总体测试统计")
print("="*80)
print(f" 测试总数: {total}")
print(f" 成功数量: {success} 个 ✓")
print(f" 失败数量: {failed} 个 ✗")
print(f" 成功率: {success/total*100:.2f}%")
print(f" 平均耗时: {avg_time:.2f}ms")
print(f" 最大耗时: {max_time:.2f}ms")
print(f" └─ 接口: {max_item['endpoint']} ({max_item['module']})")
print(f" 最小耗时: {min_time:.2f}ms")
print(f" └─ 接口: {min_item['endpoint']} ({min_item['module']})")
# 按模块统计
print("\n" + "="*80)
print("📊 各模块性能分析")
print("="*80)
modules = {}
for r in test_results:
module = r['module']
if module not in modules:
modules[module] = {
'total': 0,
'success': 0,
'times': [],
'endpoints': [],
'errors': []
}
modules[module]['total'] += 1
if r['success']:
modules[module]['success'] += 1
else:
modules[module]['errors'].append(r['endpoint'])
if r['elapsed_time_ms'] != '0':
modules[module]['times'].append(float(r['elapsed_time_ms']))
modules[module]['endpoints'].append((r['endpoint'], float(r['elapsed_time_ms'])))
# 按成功率排序
sorted_modules = sorted(modules.items(),
key=lambda x: (x[1]['success']/x[1]['total'] if x[1]['total'] > 0 else 0),
reverse=True)
for module, stats in sorted_modules:
success_rate = (stats['success'] / stats['total'] * 100) if stats['total'] > 0 else 0
avg_time = (sum(stats['times']) / len(stats['times'])) if stats['times'] else 0
max_time = max(stats['times']) if stats['times'] else 0
min_time = min(stats['times']) if stats['times'] else 0
# 确定性能等级
if success_rate >= 90:
status = "🟢 优秀"
elif success_rate >= 70:
status = "🟡 良好"
elif success_rate >= 50:
status = "🟠 一般"
else:
status = "🔴 需优化"
print(f"\n{status} {module}")
print(f" 测试数: {stats['total']} | 成功: {stats['success']} | 失败: {stats['total']-stats['success']}")
print(f" 成功率: {success_rate:.2f}%")
print(f" 平均耗时: {avg_time:.2f}ms | 最大: {max_time:.2f}ms | 最小: {min_time:.2f}ms")
# 显示失败的接口
if stats['errors']:
print(f" ⚠️ 失败接口 ({len(stats['errors'])}个):")
for err_endpoint in stats['errors'][:3]: # 最多显示3个
print(f"{err_endpoint}")
if len(stats['errors']) > 3:
print(f" • ... 还有 {len(stats['errors'])-3}")
# HTTP方法统计
print("\n" + "="*80)
print("🔧 HTTP方法分布")
print("="*80)
methods = defaultdict(lambda: {'total': 0, 'success': 0})
for r in test_results:
method = r['method']
methods[method]['total'] += 1
if r['success']:
methods[method]['success'] += 1
for method, stats in sorted(methods.items()):
success_rate = (stats['success'] / stats['total'] * 100) if stats['total'] > 0 else 0
print(f" {method:6} | 总数: {stats['total']:3} | 成功: {stats['success']:3} | 成功率: {success_rate:5.1f}%")
# 性能分布
print("\n" + "="*80)
print("⚡ 性能分布分析")
print("="*80)
fast = sum(1 for t in times if t < 100)
normal = sum(1 for t in times if 100 <= t < 500)
slow = sum(1 for t in times if 500 <= t < 1000)
very_slow = sum(1 for t in times if t >= 1000)
print(f" 🚀 极快 (<100ms): {fast:3} 个 ({fast/len(times)*100:.1f}%)")
print(f" ✅ 正常 (100-500ms): {normal:3} 个 ({normal/len(times)*100:.1f}%)")
print(f" ⚠️ 较慢 (500-1000ms): {slow:3} 个 ({slow/len(times)*100:.1f}%)")
print(f" 🐌 很慢 (>1000ms): {very_slow:3} 个 ({very_slow/len(times)*100:.1f}%)")
# 状态码分布
print("\n" + "="*80)
print("📋 HTTP状态码分布")
print("="*80)
status_codes = defaultdict(int)
for r in test_results:
status_codes[r['status_code']] += 1
for code, count in sorted(status_codes.items()):
percentage = (count / total * 100)
if code == 200:
print(f"{code}: {count:3} 个 ({percentage:.1f}%)")
elif code >= 400:
print(f"{code}: {count:3} 个 ({percentage:.1f}%)")
else:
print(f" {code}: {count:3} 个 ({percentage:.1f}%)")
# 接口文档统计
print("\n" + "="*80)
print("📚 接口文档统计")
print("="*80)
print(f" 已记录接口: {len(api_docs)}")
doc_modules = defaultdict(int)
doc_methods = defaultdict(int)
auth_required = sum(1 for d in api_docs if d['auth'] == '需要')
for doc in api_docs:
doc_modules[doc['module']] += 1
doc_methods[doc['method']] += 1
print(f" 需要认证: {auth_required}")
print(f"\n 按模块分类:")
for module, count in sorted(doc_modules.items(), key=lambda x: x[1], reverse=True):
print(f"{module}: {count}")
print(f"\n 按方法分类:")
for method, count in sorted(doc_methods.items()):
print(f"{method}: {count}")
print("\n" + ""*80)
def print_summary():
"""打印测试摘要(兼容旧版)"""
generate_data_report()
def print_config():
"""打印测试配置"""
print("测试配置:")
print("-"*80)
enabled_modules = [name for name, enabled in TEST_MODULES.items() if enabled]
disabled_modules = [name for name, enabled in TEST_MODULES.items() if not enabled]
print(f"启用的模块 ({len(enabled_modules)}个): {', '.join(enabled_modules)}")
if disabled_modules:
print(f"禁用的模块 ({len(disabled_modules)}个): {', '.join(disabled_modules)}")
print("-"*80)
def main():
"""主函数"""
print("="*80)
print("整合后端接口性能测试工具")
print(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"主服务地址: {API_BASE_URL}")
print(f"搜索服务地址: {SEARCH_API_BASE_URL}")
print("="*80)
# 打印配置
print_config()
# 登录
token = login()
if not token:
print("\n✗ 登录失败,无法继续测试")
return 1
# 执行所有测试
try:
test_basic_apis()
test_auth_apis(token)
test_dashboard_apis(token)
test_enterprise_apis(token)
test_image_apis(token)
test_log_apis(token)
test_article_apis(token)
test_employee_apis(token)
test_author_apis(token)
test_search_apis(token)
except Exception as e:
print(f"\n✗ 测试过程中出现异常: {e}")
import traceback
traceback.print_exc()
# 生成综合数据报表(控制台输出)
generate_data_report()
# 保存结果
csv_file = save_to_csv()
doc_file = save_api_docs()
md_report_file = generate_markdown_report() # 生成Markdown报表
print("\n" + "="*80)
print("✅ 测试完成!")
print("="*80)
print(f"📁 输出文件:")
print(f" • 性能数据: {csv_file}")
print(f" • 接口文档: {doc_file}")
print(f" • 测试报表: {md_report_file}")
print(f"\n💡 提示:")
print(f" • 查看Markdown报表: {md_report_file}")
print(f" • 使用 'python 查看综合测试报表.py' 查看控制台版详细报表")
print(f" • 成功率低于70%的模块需要优化")
print(f" • 耗时超过500ms的接口建议添加缓存或优化查询")
print("="*80)
return 0
if __name__ == "__main__":
try:
sys.exit(main())
except KeyboardInterrupt:
print("\n\n✗ 测试被用户中断")
sys.exit(1)
except Exception as e:
print(f"\n✗ 测试异常: {e}")
import traceback
traceback.print_exc()
sys.exit(1)