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

502 lines
16 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
测试认证接口性能并生成CSV报告和接口文档
"""
import requests
import time
import csv
from datetime import datetime
# API配置
API_BASE_URL = "http://127.0.0.1:8216"
USERNAME = "13621242430"
PASSWORD = "admin123"
# 测试结果存储
test_results = []
api_docs = []
def test_unified_login():
"""测试统一登录接口(支持手机号和用户名)"""
print("\n" + "-"*80)
print("[1/4] 测试统一登录接口...")
url = f"{API_BASE_URL}/api/auth/login"
# 测试用例1: 使用用户名登录
print(" [1] 使用用户名登录...")
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
success = response.status_code == 200
error = '' if success else response.text
print(f" 状态码: {response.status_code} - 耗时: {elapsed_time:.2f}ms")
test_results.append({
'endpoint': '/api/auth/login (用户名)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': success,
'error': error
})
# 保存token用于后续测试
token = None
if success:
token = response.json().get('data', {}).get('token')
print(f" ✓ 登录成功获取到token")
time.sleep(0.1)
except Exception as e:
print(f" 失败: {str(e)}")
test_results.append({
'endpoint': '/api/auth/login (用户名)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
token = None
# 测试用例2: 使用手机号登录
print(" [2] 使用手机号登录...")
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
success = response.status_code == 200
error = '' if success else response.text
print(f" 状态码: {response.status_code} - 耗时: {elapsed_time:.2f}ms")
test_results.append({
'endpoint': '/api/auth/login (手机号)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': success,
'error': error
})
time.sleep(0.1)
except Exception as e:
print(f" 失败: {str(e)}")
test_results.append({
'endpoint': '/api/auth/login (手机号)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 测试用例3: 错误密码
print(" [3] 测试错误密码...")
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
success = response.status_code == 401 # 期望返回401
error = '' if success else response.text
print(f" 状态码: {response.status_code} - 耗时: {elapsed_time:.2f}ms")
test_results.append({
'endpoint': '/api/auth/login (错误密码)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': success,
'error': error
})
time.sleep(0.1)
except Exception as e:
print(f" 失败: {str(e)}")
test_results.append({
'endpoint': '/api/auth/login (错误密码)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 测试用例4: 缺少参数
print(" [4] 测试缺少参数...")
data = {"username": USERNAME} # 缺少password
try:
start_time = time.time()
response = requests.post(url, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
success = response.status_code == 400 # 期望返回400
error = '' if success else response.text
print(f" 状态码: {response.status_code} - 耗时: {elapsed_time:.2f}ms")
test_results.append({
'endpoint': '/api/auth/login (缺少参数)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': success,
'error': error
})
except Exception as e:
print(f" 失败: {str(e)}")
test_results.append({
'endpoint': '/api/auth/login (缺少参数)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 添加接口文档
api_docs.append({
'endpoint': '/api/auth/login',
'method': 'POST',
'description': '统一登录接口(支持企业主和员工,支持手机号或用户名登录)',
'auth': '无需认证',
'params': 'username/phone (二选一), password',
'response': '返回token和用户信息含企业信息'
})
return token
def test_employee_login():
"""测试员工登录接口"""
print("\n" + "-"*80)
print("[2/4] 测试员工登录接口...")
url = f"{API_BASE_URL}/api/auth/employee/login"
# 测试用例1: 正常登录
print(" [1] 员工正常登录...")
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
success = response.status_code == 200
error = '' if success else response.text
print(f" 状态码: {response.status_code} - 耗时: {elapsed_time:.2f}ms")
test_results.append({
'endpoint': '/api/auth/employee/login',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': success,
'error': error
})
time.sleep(0.1)
except Exception as e:
print(f" 失败: {str(e)}")
test_results.append({
'endpoint': '/api/auth/employee/login',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 测试用例2: 错误密码
print(" [2] 员工错误密码...")
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
success = response.status_code == 401
error = '' if success else response.text
print(f" 状态码: {response.status_code} - 耗时: {elapsed_time:.2f}ms")
test_results.append({
'endpoint': '/api/auth/employee/login (错误密码)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': success,
'error': error
})
except Exception as e:
print(f" 失败: {str(e)}")
test_results.append({
'endpoint': '/api/auth/employee/login (错误密码)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 添加接口文档
api_docs.append({
'endpoint': '/api/auth/employee/login',
'method': 'POST',
'description': '员工登录接口(仅支持手机号登录)',
'auth': '无需认证',
'params': 'phone, password',
'response': '返回token和员工信息含企业信息、小红书绑定状态'
})
def test_logout(token):
"""测试用户登出接口"""
print("\n" + "-"*80)
print("[3/4] 测试用户登出接口...")
url = f"{API_BASE_URL}/api/auth/logout"
# 测试用例1: 带token登出
if token:
print(" [1] 带token登出...")
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
success = response.status_code == 200
error = '' if success else response.text
print(f" 状态码: {response.status_code} - 耗时: {elapsed_time:.2f}ms")
test_results.append({
'endpoint': '/api/auth/logout (带token)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': success,
'error': error
})
time.sleep(0.1)
except Exception as e:
print(f" 失败: {str(e)}")
test_results.append({
'endpoint': '/api/auth/logout (带token)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 测试用例2: 不带token登出
print(" [2] 不带token登出...")
try:
start_time = time.time()
response = requests.post(url, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
success = response.status_code == 200
error = '' if success else response.text
print(f" 状态码: {response.status_code} - 耗时: {elapsed_time:.2f}ms")
test_results.append({
'endpoint': '/api/auth/logout (不带token)',
'method': 'POST',
'status_code': response.status_code,
'elapsed_time_ms': f"{elapsed_time:.2f}",
'success': success,
'error': error
})
except Exception as e:
print(f" 失败: {str(e)}")
test_results.append({
'endpoint': '/api/auth/logout (不带token)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
# 添加接口文档
api_docs.append({
'endpoint': '/api/auth/logout',
'method': 'POST',
'description': '用户登出接口',
'auth': '可选建议带token',
'params': '',
'response': '返回登出成功消息'
})
def test_concurrent_login():
"""测试并发登录性能"""
print("\n" + "-"*80)
print("[4/4] 测试并发登录性能...")
url = f"{API_BASE_URL}/api/auth/login"
data = {"username": USERNAME, "password": PASSWORD}
concurrent_count = 5
print(f" 同时发起{concurrent_count}个登录请求...")
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=concurrent_count) as executor:
overall_start = time.time()
futures = [executor.submit(single_login) for _ in range(concurrent_count)]
results = [f.result() for f in concurrent.futures.as_completed(futures)]
overall_time = (time.time() - overall_start) * 1000
success_count = sum(1 for status, _ in results if status == 200)
avg_time = sum(t for _, t in results) / len(results)
print(f" 总耗时: {overall_time:.2f}ms")
print(f" 成功数: {success_count}/{concurrent_count}")
print(f" 平均单次耗时: {avg_time:.2f}ms")
test_results.append({
'endpoint': f'/api/auth/login (并发{concurrent_count}个)',
'method': 'POST',
'status_code': 200 if success_count == concurrent_count else 'mixed',
'elapsed_time_ms': f"{avg_time:.2f}",
'success': success_count == concurrent_count,
'error': f'成功{success_count}/{concurrent_count}, 总耗时{overall_time:.2f}ms'
})
except Exception as e:
print(f" 失败: {str(e)}")
test_results.append({
'endpoint': f'/api/auth/login (并发{concurrent_count}个)',
'method': 'POST',
'status_code': 0,
'elapsed_time_ms': '0',
'success': False,
'error': str(e)
})
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=[
'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=[
'endpoint', 'method', 'description', 'auth', 'params', 'response'
])
writer.writeheader()
writer.writerows(api_docs)
print(f"✓ 接口文档已保存到: {filename}")
return filename
def print_summary():
"""打印测试摘要"""
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
print(f"总测试数: {total}")
print(f"成功: {success} ({success/total*100:.1f}%)")
print(f"失败: {failed} ({failed/total*100:.1f}%)")
print(f"平均耗时: {avg_time:.2f}ms")
print(f"最大耗时: {max_time:.2f}ms")
print(f"最小耗时: {min_time:.2f}ms")
print("="*80)
def main():
"""主函数"""
print("="*80)
print("认证接口性能测试工具")
print(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"API地址: {API_BASE_URL}")
print("="*80)
# 执行所有测试
token = test_unified_login()
test_employee_login()
test_logout(token)
test_concurrent_login()
# 打印摘要
print_summary()
# 保存结果
csv_file = save_to_csv()
doc_file = save_api_docs()
print(f"\n✓ 测试完成!")
print(f" - 性能数据: {csv_file}")
print(f" - 接口文档: {doc_file}")
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n\n✗ 测试被用户中断")
except Exception as e:
print(f"\n✗ 测试异常: {e}")
import traceback
traceback.print_exc()