feature/网络管理和Web部署系统 #2
183
scripts/network/ApiTestScript.gd
Normal file
183
scripts/network/ApiTestScript.gd
Normal file
@@ -0,0 +1,183 @@
|
||||
extends Node
|
||||
|
||||
# API测试脚本 - 验证更新后的接口逻辑
|
||||
class_name ApiTestScript
|
||||
|
||||
# 测试用例
|
||||
var test_cases = [
|
||||
{
|
||||
"name": "测试网络连接",
|
||||
"operation": "network_test",
|
||||
"method": "get_app_status"
|
||||
},
|
||||
{
|
||||
"name": "测试发送邮箱验证码",
|
||||
"operation": "send_code",
|
||||
"method": "send_email_verification",
|
||||
"params": ["test@example.com"]
|
||||
},
|
||||
{
|
||||
"name": "测试邮箱冲突检测",
|
||||
"operation": "send_code",
|
||||
"method": "send_email_verification",
|
||||
"params": ["existing@example.com"] # 假设这个邮箱已存在
|
||||
},
|
||||
{
|
||||
"name": "测试登录",
|
||||
"operation": "login",
|
||||
"method": "login",
|
||||
"params": ["testuser", "password123"]
|
||||
},
|
||||
{
|
||||
"name": "测试注册",
|
||||
"operation": "register",
|
||||
"method": "register",
|
||||
"params": ["newuser", "newpassword123", "新用户", "newuser@example.com", "123456"]
|
||||
}
|
||||
]
|
||||
|
||||
func _ready():
|
||||
print("=== API测试脚本启动 ===")
|
||||
print("测试最新API v1.1.1的接口逻辑和toast显示")
|
||||
|
||||
# 延迟一下确保NetworkManager已初始化
|
||||
await get_tree().create_timer(1.0).timeout
|
||||
|
||||
# 运行测试用例
|
||||
run_tests()
|
||||
|
||||
func run_tests():
|
||||
print("\n🧪 开始运行API测试用例...")
|
||||
|
||||
for i in range(test_cases.size()):
|
||||
var test_case = test_cases[i]
|
||||
print("\n--- 测试 %d: %s ---" % [i + 1, test_case.name])
|
||||
|
||||
await run_single_test(test_case)
|
||||
|
||||
# 测试间隔
|
||||
await get_tree().create_timer(2.0).timeout
|
||||
|
||||
print("\n✅ 所有测试用例执行完成")
|
||||
|
||||
func run_single_test(test_case: Dictionary):
|
||||
var operation = test_case.operation
|
||||
var method = test_case.method
|
||||
var params = test_case.get("params", [])
|
||||
|
||||
print("操作类型: ", operation)
|
||||
print("调用方法: ", method)
|
||||
print("参数: ", params)
|
||||
|
||||
# 创建回调函数
|
||||
var callback = func(success: bool, data: Dictionary, error_info: Dictionary):
|
||||
handle_test_response(test_case.name, operation, success, data, error_info)
|
||||
|
||||
# 调用对应的NetworkManager方法
|
||||
var request_id = ""
|
||||
match method:
|
||||
"get_app_status":
|
||||
request_id = NetworkManager.get_app_status(callback)
|
||||
"send_email_verification":
|
||||
if params.size() > 0:
|
||||
request_id = NetworkManager.send_email_verification(params[0], callback)
|
||||
"login":
|
||||
if params.size() >= 2:
|
||||
request_id = NetworkManager.login(params[0], params[1], callback)
|
||||
"register":
|
||||
if params.size() >= 5:
|
||||
request_id = NetworkManager.register(params[0], params[1], params[2], params[3], params[4], callback)
|
||||
_:
|
||||
print("❌ 未知的测试方法: ", method)
|
||||
return
|
||||
|
||||
if request_id != "":
|
||||
print("✅ 请求已发送,ID: ", request_id)
|
||||
else:
|
||||
print("❌ 请求发送失败")
|
||||
|
||||
func handle_test_response(test_name: String, operation: String, success: bool, data: Dictionary, error_info: Dictionary):
|
||||
print("\n=== %s 响应结果 ===" % test_name)
|
||||
print("成功: ", success)
|
||||
print("数据: ", data)
|
||||
print("错误信息: ", error_info)
|
||||
|
||||
# 使用ResponseHandler处理响应
|
||||
var result = ResponseHandler.handle_response(operation, success, data, error_info)
|
||||
|
||||
print("\n--- ResponseHandler处理结果 ---")
|
||||
print("处理成功: ", result.success)
|
||||
print("消息: ", result.message)
|
||||
print("Toast类型: ", result.toast_type)
|
||||
print("是否显示Toast: ", result.should_show_toast)
|
||||
|
||||
# 模拟Toast显示
|
||||
if result.should_show_toast:
|
||||
print("🍞 Toast显示: [%s] %s" % [result.toast_type.to_upper(), result.message])
|
||||
|
||||
# 检查特殊情况
|
||||
check_special_cases(data, error_info)
|
||||
|
||||
func check_special_cases(data: Dictionary, error_info: Dictionary):
|
||||
var response_code = error_info.get("response_code", 0)
|
||||
var error_code = data.get("error_code", "")
|
||||
|
||||
print("\n--- 特殊情况检查 ---")
|
||||
|
||||
# 检查409冲突
|
||||
if response_code == 409:
|
||||
print("✅ 检测到409冲突状态码 - 邮箱冲突检测正常工作")
|
||||
|
||||
# 检查206测试模式
|
||||
if response_code == 206 or error_code == "TEST_MODE_ONLY":
|
||||
print("✅ 检测到206测试模式 - 测试模式处理正常工作")
|
||||
if data.has("data") and data.data.has("verification_code"):
|
||||
print("🔑 测试模式验证码: ", data.data.verification_code)
|
||||
|
||||
# 检查429频率限制
|
||||
if response_code == 429 or error_code == "TOO_MANY_REQUESTS":
|
||||
print("✅ 检测到429频率限制 - 频率限制处理正常工作")
|
||||
if data.has("throttle_info"):
|
||||
print("⏰ 限制信息: ", data.throttle_info)
|
||||
|
||||
# 检查其他重要状态码
|
||||
match response_code:
|
||||
200:
|
||||
print("✅ 200 成功响应")
|
||||
201:
|
||||
print("✅ 201 创建成功")
|
||||
400:
|
||||
print("⚠️ 400 请求参数错误")
|
||||
401:
|
||||
print("⚠️ 401 认证失败")
|
||||
404:
|
||||
print("⚠️ 404 资源不存在")
|
||||
500:
|
||||
print("❌ 500 服务器内部错误")
|
||||
503:
|
||||
print("❌ 503 服务不可用")
|
||||
|
||||
# 手动触发测试的方法
|
||||
func test_email_conflict():
|
||||
print("\n🧪 手动测试邮箱冲突检测...")
|
||||
var callback = func(success: bool, data: Dictionary, error_info: Dictionary):
|
||||
handle_test_response("邮箱冲突测试", "send_code", success, data, error_info)
|
||||
|
||||
NetworkManager.send_email_verification("existing@example.com", callback)
|
||||
|
||||
func test_rate_limit():
|
||||
print("\n🧪 手动测试频率限制...")
|
||||
var callback = func(success: bool, data: Dictionary, error_info: Dictionary):
|
||||
handle_test_response("频率限制测试", "send_code", success, data, error_info)
|
||||
|
||||
# 快速发送多个请求来触发频率限制
|
||||
for i in range(3):
|
||||
NetworkManager.send_email_verification("test@example.com", callback)
|
||||
await get_tree().create_timer(0.1).timeout
|
||||
|
||||
func test_test_mode():
|
||||
print("\n🧪 手动测试测试模式...")
|
||||
var callback = func(success: bool, data: Dictionary, error_info: Dictionary):
|
||||
handle_test_response("测试模式测试", "send_code", success, data, error_info)
|
||||
|
||||
NetworkManager.send_email_verification("testmode@example.com", callback)
|
||||
1
scripts/network/ApiTestScript.gd.uid
Normal file
1
scripts/network/ApiTestScript.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://4gamylhvy4nn
|
||||
1
scripts/web_font_handler.gd.uid
Normal file
1
scripts/web_font_handler.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dvgsil07gh4tl
|
||||
@@ -4,7 +4,39 @@
|
||||
|
||||
## 测试脚本说明
|
||||
|
||||
### 1. `simple_api_test.py` - 简化版测试
|
||||
### 1. `quick_test.py` - 快速测试(推荐)
|
||||
快速验证API接口的基本功能,适合日常检查。
|
||||
|
||||
**使用方法:**
|
||||
```bash
|
||||
python tests/api/quick_test.py
|
||||
```
|
||||
|
||||
**测试内容:**
|
||||
- ✅ 应用状态检查
|
||||
- ✅ 发送邮箱验证码
|
||||
- ✅ 发送验证码(无效邮箱)
|
||||
- ✅ 用户登录
|
||||
- ✅ 用户注册(无邮箱)
|
||||
- ✅ 发送登录验证码
|
||||
|
||||
### 2. `api_client_test.py` - 完整测试套件
|
||||
全面的API接口测试,包含所有业务流程和错误场景。
|
||||
|
||||
**使用方法:**
|
||||
```bash
|
||||
python tests/api/api_client_test.py
|
||||
```
|
||||
|
||||
**测试内容:**
|
||||
- 🔄 完整的邮箱验证流程
|
||||
- 🔄 用户注册流程(带邮箱验证)
|
||||
- 🔄 用户登录流程(密码+验证码)
|
||||
- 🔄 密码重置流程
|
||||
- 🔄 错误场景测试
|
||||
- 🔄 频率限制测试
|
||||
|
||||
### 3. `simple_api_test.py` - 简化版测试
|
||||
快速验证API接口的基本连通性和功能。
|
||||
|
||||
**使用方法:**
|
||||
@@ -24,7 +56,7 @@ python tests/api/simple_api_test.py http://localhost:3000
|
||||
- ✅ 无效登录测试
|
||||
- ✅ 管理员登录测试
|
||||
|
||||
### 2. `api_test.py` - 完整版测试
|
||||
### 4. `api_test.py` - 完整版测试
|
||||
全面的API接口测试,包括边界条件和错误处理。
|
||||
|
||||
**使用方法:**
|
||||
@@ -143,8 +175,19 @@ tester.run_basic_tests()
|
||||
|
||||
## 依赖要求
|
||||
|
||||
### 安装依赖
|
||||
```bash
|
||||
# 安装Python依赖
|
||||
pip install -r tests/api/requirements.txt
|
||||
|
||||
# 或者手动安装
|
||||
pip install requests
|
||||
```
|
||||
|
||||
测试脚本使用Python标准库和requests库,无需额外依赖。
|
||||
### 依赖包说明
|
||||
- **requests** - HTTP请求库,用于发送API请求
|
||||
- **json** - JSON数据处理(Python标准库)
|
||||
- **time** - 时间处理(Python标准库)
|
||||
- **sys** - 系统功能(Python标准库)
|
||||
|
||||
测试脚本主要使用Python标准库和requests库,依赖最小化。
|
||||
427
tests/api/api_client_test.py
Normal file
427
tests/api/api_client_test.py
Normal file
@@ -0,0 +1,427 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
API客户端测试脚本
|
||||
用于在没有Godot引擎的情况下测试后端API接口
|
||||
|
||||
使用方法:
|
||||
python api_client_test.py
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
import sys
|
||||
from typing import Dict, Any, Optional
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
|
||||
# API配置
|
||||
API_BASE_URL = "https://whaletownend.xinghangee.icu"
|
||||
DEFAULT_TIMEOUT = 30
|
||||
|
||||
@dataclass
|
||||
class TestResult:
|
||||
"""测试结果数据类"""
|
||||
success: bool
|
||||
message: str
|
||||
response_code: int
|
||||
response_data: Dict[str, Any]
|
||||
error_info: Optional[Dict[str, Any]] = None
|
||||
execution_time: float = 0.0
|
||||
|
||||
class APIClient:
|
||||
"""API客户端类"""
|
||||
|
||||
def __init__(self, base_url: str = API_BASE_URL):
|
||||
self.base_url = base_url
|
||||
self.session = requests.Session()
|
||||
self.session.headers.update({
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': 'WhaleTown-API-Test/1.0'
|
||||
})
|
||||
|
||||
def _make_request(self, method: str, endpoint: str, data: Optional[Dict] = None,
|
||||
timeout: int = DEFAULT_TIMEOUT) -> TestResult:
|
||||
"""发送HTTP请求"""
|
||||
url = f"{self.base_url}{endpoint}"
|
||||
start_time = time.time()
|
||||
|
||||
try:
|
||||
print(f"🚀 发送 {method} 请求到: {url}")
|
||||
if data:
|
||||
print(f"📦 请求数据: {json.dumps(data, ensure_ascii=False, indent=2)}")
|
||||
|
||||
response = self.session.request(
|
||||
method=method,
|
||||
url=url,
|
||||
json=data if data else None,
|
||||
timeout=timeout
|
||||
)
|
||||
|
||||
execution_time = time.time() - start_time
|
||||
|
||||
print(f"📊 响应状态码: {response.status_code}")
|
||||
print(f"⏱️ 执行时间: {execution_time:.3f}s")
|
||||
|
||||
# 尝试解析JSON响应
|
||||
try:
|
||||
response_data = response.json()
|
||||
print(f"📄 响应数据: {json.dumps(response_data, ensure_ascii=False, indent=2)}")
|
||||
except json.JSONDecodeError:
|
||||
response_data = {"raw_response": response.text}
|
||||
print(f"📄 原始响应: {response.text}")
|
||||
|
||||
# 判断请求是否成功
|
||||
is_success = False
|
||||
if 200 <= response.status_code < 300:
|
||||
# HTTP成功状态码
|
||||
business_success = response_data.get("success", True)
|
||||
if business_success:
|
||||
is_success = True
|
||||
elif response.status_code == 206 and response_data.get("error_code") == "TEST_MODE_ONLY":
|
||||
# 测试模式也算成功
|
||||
is_success = True
|
||||
|
||||
return TestResult(
|
||||
success=is_success,
|
||||
message=response_data.get("message", ""),
|
||||
response_code=response.status_code,
|
||||
response_data=response_data,
|
||||
execution_time=execution_time
|
||||
)
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
execution_time = time.time() - start_time
|
||||
return TestResult(
|
||||
success=False,
|
||||
message="请求超时",
|
||||
response_code=0,
|
||||
response_data={},
|
||||
error_info={"error_type": "TIMEOUT"},
|
||||
execution_time=execution_time
|
||||
)
|
||||
except requests.exceptions.ConnectionError:
|
||||
execution_time = time.time() - start_time
|
||||
return TestResult(
|
||||
success=False,
|
||||
message="网络连接失败",
|
||||
response_code=0,
|
||||
response_data={},
|
||||
error_info={"error_type": "CONNECTION_ERROR"},
|
||||
execution_time=execution_time
|
||||
)
|
||||
except Exception as e:
|
||||
execution_time = time.time() - start_time
|
||||
return TestResult(
|
||||
success=False,
|
||||
message=f"请求异常: {str(e)}",
|
||||
response_code=0,
|
||||
response_data={},
|
||||
error_info={"error_type": "UNKNOWN_ERROR", "details": str(e)},
|
||||
execution_time=execution_time
|
||||
)
|
||||
|
||||
def get_app_status(self) -> TestResult:
|
||||
"""获取应用状态"""
|
||||
return self._make_request("GET", "/")
|
||||
|
||||
def login(self, identifier: str, password: str) -> TestResult:
|
||||
"""用户登录"""
|
||||
data = {
|
||||
"identifier": identifier,
|
||||
"password": password
|
||||
}
|
||||
return self._make_request("POST", "/auth/login", data)
|
||||
|
||||
def register(self, username: str, password: str, nickname: str,
|
||||
email: str = "", email_verification_code: str = "") -> TestResult:
|
||||
"""用户注册"""
|
||||
data = {
|
||||
"username": username,
|
||||
"password": password,
|
||||
"nickname": nickname
|
||||
}
|
||||
|
||||
if email:
|
||||
data["email"] = email
|
||||
if email_verification_code:
|
||||
data["email_verification_code"] = email_verification_code
|
||||
|
||||
return self._make_request("POST", "/auth/register", data)
|
||||
|
||||
def send_email_verification(self, email: str) -> TestResult:
|
||||
"""发送邮箱验证码"""
|
||||
data = {"email": email}
|
||||
return self._make_request("POST", "/auth/send-email-verification", data)
|
||||
|
||||
def verify_email(self, email: str, verification_code: str) -> TestResult:
|
||||
"""验证邮箱验证码"""
|
||||
data = {
|
||||
"email": email,
|
||||
"verification_code": verification_code
|
||||
}
|
||||
return self._make_request("POST", "/auth/verify-email", data)
|
||||
|
||||
def send_login_verification_code(self, identifier: str) -> TestResult:
|
||||
"""发送登录验证码"""
|
||||
data = {"identifier": identifier}
|
||||
return self._make_request("POST", "/auth/send-login-verification-code", data)
|
||||
|
||||
def verification_code_login(self, identifier: str, verification_code: str) -> TestResult:
|
||||
"""验证码登录"""
|
||||
data = {
|
||||
"identifier": identifier,
|
||||
"verification_code": verification_code
|
||||
}
|
||||
return self._make_request("POST", "/auth/verification-code-login", data)
|
||||
|
||||
def forgot_password(self, identifier: str) -> TestResult:
|
||||
"""忘记密码 - 发送重置验证码"""
|
||||
data = {"identifier": identifier}
|
||||
return self._make_request("POST", "/auth/forgot-password", data)
|
||||
|
||||
def reset_password(self, identifier: str, verification_code: str, new_password: str) -> TestResult:
|
||||
"""重置密码"""
|
||||
data = {
|
||||
"identifier": identifier,
|
||||
"verification_code": verification_code,
|
||||
"new_password": new_password
|
||||
}
|
||||
return self._make_request("POST", "/auth/reset-password", data)
|
||||
|
||||
class APITester:
|
||||
"""API测试器"""
|
||||
|
||||
def __init__(self):
|
||||
self.client = APIClient()
|
||||
self.test_results = []
|
||||
self.test_email = "test@example.com"
|
||||
self.test_username = "testuser"
|
||||
self.test_password = "password123"
|
||||
self.verification_code = None
|
||||
|
||||
def print_header(self, title: str):
|
||||
"""打印测试标题"""
|
||||
print("\n" + "="*60)
|
||||
print(f"🧪 {title}")
|
||||
print("="*60)
|
||||
|
||||
def print_result(self, test_name: str, result: TestResult):
|
||||
"""打印测试结果"""
|
||||
status = "✅ 成功" if result.success else "❌ 失败"
|
||||
print(f"\n📋 测试: {test_name}")
|
||||
print(f"🎯 结果: {status}")
|
||||
print(f"💬 消息: {result.message}")
|
||||
print(f"📊 状态码: {result.response_code}")
|
||||
print(f"⏱️ 耗时: {result.execution_time:.3f}s")
|
||||
|
||||
# 检查特殊情况
|
||||
if result.response_code == 206:
|
||||
print("🧪 检测到测试模式响应")
|
||||
elif result.response_code == 409:
|
||||
print("⚠️ 检测到资源冲突")
|
||||
elif result.response_code == 429:
|
||||
print("⏰ 检测到频率限制")
|
||||
|
||||
# 提取验证码(如果有)
|
||||
if result.response_data.get("data", {}).get("verification_code"):
|
||||
self.verification_code = result.response_data["data"]["verification_code"]
|
||||
print(f"🔑 获取到验证码: {self.verification_code}")
|
||||
|
||||
self.test_results.append((test_name, result))
|
||||
print("-" * 40)
|
||||
|
||||
def test_app_status(self):
|
||||
"""测试应用状态"""
|
||||
self.print_header("应用状态测试")
|
||||
result = self.client.get_app_status()
|
||||
self.print_result("获取应用状态", result)
|
||||
|
||||
def test_email_verification_flow(self):
|
||||
"""测试邮箱验证流程"""
|
||||
self.print_header("邮箱验证流程测试")
|
||||
|
||||
# 1. 发送邮箱验证码
|
||||
result = self.client.send_email_verification(self.test_email)
|
||||
self.print_result("发送邮箱验证码", result)
|
||||
|
||||
if self.verification_code:
|
||||
# 2. 验证邮箱验证码
|
||||
result = self.client.verify_email(self.test_email, self.verification_code)
|
||||
self.print_result("验证邮箱验证码", result)
|
||||
|
||||
def test_registration_flow(self):
|
||||
"""测试注册流程"""
|
||||
self.print_header("用户注册流程测试")
|
||||
|
||||
# 使用之前获取的验证码进行注册
|
||||
if self.verification_code:
|
||||
result = self.client.register(
|
||||
username=self.test_username,
|
||||
password=self.test_password,
|
||||
nickname="测试用户",
|
||||
email=self.test_email,
|
||||
email_verification_code=self.verification_code
|
||||
)
|
||||
self.print_result("用户注册(带邮箱验证)", result)
|
||||
else:
|
||||
# 无邮箱注册
|
||||
result = self.client.register(
|
||||
username=f"{self.test_username}_no_email",
|
||||
password=self.test_password,
|
||||
nickname="测试用户(无邮箱)"
|
||||
)
|
||||
self.print_result("用户注册(无邮箱)", result)
|
||||
|
||||
def test_login_flow(self):
|
||||
"""测试登录流程"""
|
||||
self.print_header("用户登录流程测试")
|
||||
|
||||
# 1. 密码登录
|
||||
result = self.client.login(self.test_username, self.test_password)
|
||||
self.print_result("密码登录", result)
|
||||
|
||||
# 2. 发送登录验证码
|
||||
result = self.client.send_login_verification_code(self.test_email)
|
||||
self.print_result("发送登录验证码", result)
|
||||
|
||||
# 3. 验证码登录
|
||||
if self.verification_code:
|
||||
result = self.client.verification_code_login(self.test_email, self.verification_code)
|
||||
self.print_result("验证码登录", result)
|
||||
|
||||
def test_password_reset_flow(self):
|
||||
"""测试密码重置流程"""
|
||||
self.print_header("密码重置流程测试")
|
||||
|
||||
# 1. 发送重置验证码
|
||||
result = self.client.forgot_password(self.test_email)
|
||||
self.print_result("发送重置验证码", result)
|
||||
|
||||
# 2. 重置密码
|
||||
if self.verification_code:
|
||||
result = self.client.reset_password(
|
||||
identifier=self.test_email,
|
||||
verification_code=self.verification_code,
|
||||
new_password="newpassword123"
|
||||
)
|
||||
self.print_result("重置密码", result)
|
||||
|
||||
def test_error_scenarios(self):
|
||||
"""测试错误场景"""
|
||||
self.print_header("错误场景测试")
|
||||
|
||||
# 1. 无效邮箱格式
|
||||
result = self.client.send_email_verification("invalid-email")
|
||||
self.print_result("无效邮箱格式", result)
|
||||
|
||||
# 2. 错误的验证码
|
||||
result = self.client.verify_email(self.test_email, "000000")
|
||||
self.print_result("错误验证码", result)
|
||||
|
||||
# 3. 用户名冲突
|
||||
result = self.client.register(
|
||||
username=self.test_username, # 重复用户名
|
||||
password=self.test_password,
|
||||
nickname="重复用户"
|
||||
)
|
||||
self.print_result("用户名冲突", result)
|
||||
|
||||
# 4. 错误的登录凭据
|
||||
result = self.client.login("nonexistent", "wrongpassword")
|
||||
self.print_result("错误登录凭据", result)
|
||||
|
||||
def test_rate_limiting(self):
|
||||
"""测试频率限制"""
|
||||
self.print_header("频率限制测试")
|
||||
|
||||
print("🔄 快速发送多个验证码请求以触发频率限制...")
|
||||
for i in range(3):
|
||||
result = self.client.send_email_verification(f"test{i}@example.com")
|
||||
self.print_result(f"验证码请求 #{i+1}", result)
|
||||
|
||||
if result.response_code == 429:
|
||||
print("✅ 成功触发频率限制")
|
||||
break
|
||||
|
||||
time.sleep(0.5) # 短暂延迟
|
||||
|
||||
def run_all_tests(self):
|
||||
"""运行所有测试"""
|
||||
print("🎯 开始API接口测试")
|
||||
print(f"🌐 测试服务器: {API_BASE_URL}")
|
||||
print(f"📧 测试邮箱: {self.test_email}")
|
||||
print(f"👤 测试用户名: {self.test_username}")
|
||||
|
||||
try:
|
||||
# 基础测试
|
||||
self.test_app_status()
|
||||
|
||||
# 邮箱验证流程
|
||||
self.test_email_verification_flow()
|
||||
|
||||
# 注册流程
|
||||
self.test_registration_flow()
|
||||
|
||||
# 登录流程
|
||||
self.test_login_flow()
|
||||
|
||||
# 密码重置流程
|
||||
self.test_password_reset_flow()
|
||||
|
||||
# 错误场景测试
|
||||
self.test_error_scenarios()
|
||||
|
||||
# 频率限制测试
|
||||
self.test_rate_limiting()
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n⚠️ 测试被用户中断")
|
||||
except Exception as e:
|
||||
print(f"\n❌ 测试过程中发生异常: {e}")
|
||||
finally:
|
||||
self.print_summary()
|
||||
|
||||
def print_summary(self):
|
||||
"""打印测试总结"""
|
||||
self.print_header("测试总结")
|
||||
|
||||
total_tests = len(self.test_results)
|
||||
successful_tests = sum(1 for _, result in self.test_results if result.success)
|
||||
failed_tests = total_tests - successful_tests
|
||||
|
||||
print(f"📊 总测试数: {total_tests}")
|
||||
print(f"✅ 成功: {successful_tests}")
|
||||
print(f"❌ 失败: {failed_tests}")
|
||||
print(f"📈 成功率: {(successful_tests/total_tests*100):.1f}%" if total_tests > 0 else "0%")
|
||||
|
||||
if failed_tests > 0:
|
||||
print("\n❌ 失败的测试:")
|
||||
for test_name, result in self.test_results:
|
||||
if not result.success:
|
||||
print(f" • {test_name}: {result.message} (状态码: {result.response_code})")
|
||||
|
||||
print(f"\n⏱️ 总执行时间: {sum(result.execution_time for _, result in self.test_results):.3f}s")
|
||||
print("🎉 测试完成!")
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("🐋 WhaleTown API 接口测试工具")
|
||||
print("=" * 60)
|
||||
|
||||
# 检查网络连接
|
||||
try:
|
||||
response = requests.get(API_BASE_URL, timeout=5)
|
||||
print(f"✅ 服务器连接正常 (状态码: {response.status_code})")
|
||||
except Exception as e:
|
||||
print(f"❌ 无法连接到服务器: {e}")
|
||||
print("请检查网络连接或服务器地址")
|
||||
sys.exit(1)
|
||||
|
||||
# 运行测试
|
||||
tester = APITester()
|
||||
tester.run_all_tests()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
150
tests/api/quick_test.py
Normal file
150
tests/api/quick_test.py
Normal file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
快速API测试脚本
|
||||
用于快速验证API接口的基本功能
|
||||
|
||||
使用方法:
|
||||
python quick_test.py
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import sys
|
||||
|
||||
# API配置
|
||||
API_BASE_URL = "https://whaletownend.xinghangee.icu"
|
||||
|
||||
def test_api_endpoint(method, endpoint, data=None, description=""):
|
||||
"""测试单个API端点"""
|
||||
url = f"{API_BASE_URL}{endpoint}"
|
||||
|
||||
print(f"\n🧪 测试: {description}")
|
||||
print(f"📡 {method} {url}")
|
||||
|
||||
if data:
|
||||
print(f"📦 数据: {json.dumps(data, ensure_ascii=False)}")
|
||||
|
||||
try:
|
||||
if method == "GET":
|
||||
response = requests.get(url, timeout=10)
|
||||
elif method == "POST":
|
||||
response = requests.post(url, json=data, timeout=10)
|
||||
else:
|
||||
print(f"❌ 不支持的方法: {method}")
|
||||
return False
|
||||
|
||||
print(f"📊 状态码: {response.status_code}")
|
||||
|
||||
try:
|
||||
response_data = response.json()
|
||||
print(f"📄 响应: {json.dumps(response_data, ensure_ascii=False, indent=2)}")
|
||||
|
||||
# 检查特殊状态码
|
||||
if response.status_code == 206:
|
||||
print("🧪 测试模式响应")
|
||||
if response_data.get("data", {}).get("verification_code"):
|
||||
print(f"🔑 验证码: {response_data['data']['verification_code']}")
|
||||
elif response.status_code == 409:
|
||||
print("⚠️ 资源冲突")
|
||||
elif response.status_code == 429:
|
||||
print("⏰ 频率限制")
|
||||
|
||||
return 200 <= response.status_code < 300 or response.status_code == 206
|
||||
|
||||
except json.JSONDecodeError:
|
||||
print(f"📄 原始响应: {response.text}")
|
||||
return 200 <= response.status_code < 300
|
||||
|
||||
except requests.exceptions.Timeout:
|
||||
print("❌ 请求超时")
|
||||
return False
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("❌ 连接失败")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"❌ 请求异常: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("🐋 WhaleTown API 快速测试")
|
||||
print("=" * 50)
|
||||
|
||||
# 测试用例
|
||||
tests = [
|
||||
{
|
||||
"method": "GET",
|
||||
"endpoint": "/",
|
||||
"description": "获取应用状态"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"endpoint": "/auth/send-email-verification",
|
||||
"data": {"email": "test@example.com"},
|
||||
"description": "发送邮箱验证码"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"endpoint": "/auth/send-email-verification",
|
||||
"data": {"email": "invalid-email"},
|
||||
"description": "发送验证码(无效邮箱)"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"endpoint": "/auth/login",
|
||||
"data": {"identifier": "testuser", "password": "password123"},
|
||||
"description": "用户登录"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"endpoint": "/auth/register",
|
||||
"data": {
|
||||
"username": "testuser_quick",
|
||||
"password": "password123",
|
||||
"nickname": "快速测试用户"
|
||||
},
|
||||
"description": "用户注册(无邮箱)"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"endpoint": "/auth/send-login-verification-code",
|
||||
"data": {"identifier": "test@example.com"},
|
||||
"description": "发送登录验证码"
|
||||
}
|
||||
]
|
||||
|
||||
# 执行测试
|
||||
success_count = 0
|
||||
total_count = len(tests)
|
||||
|
||||
for test in tests:
|
||||
success = test_api_endpoint(
|
||||
method=test["method"],
|
||||
endpoint=test["endpoint"],
|
||||
data=test.get("data"),
|
||||
description=test["description"]
|
||||
)
|
||||
|
||||
if success:
|
||||
success_count += 1
|
||||
print("✅ 测试通过")
|
||||
else:
|
||||
print("❌ 测试失败")
|
||||
|
||||
print("-" * 30)
|
||||
|
||||
# 打印总结
|
||||
print(f"\n📊 测试总结:")
|
||||
print(f"总测试数: {total_count}")
|
||||
print(f"成功: {success_count}")
|
||||
print(f"失败: {total_count - success_count}")
|
||||
print(f"成功率: {(success_count/total_count*100):.1f}%")
|
||||
|
||||
if success_count == total_count:
|
||||
print("🎉 所有测试通过!")
|
||||
else:
|
||||
print("⚠️ 部分测试失败,请检查API服务")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
2
tests/api/requirements.txt
Normal file
2
tests/api/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
# Python API测试依赖包
|
||||
requests>=2.25.0
|
||||
55
tests/api/run_tests.bat
Normal file
55
tests/api/run_tests.bat
Normal file
@@ -0,0 +1,55 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
echo 🐋 WhaleTown API 测试工具
|
||||
echo ========================
|
||||
|
||||
echo.
|
||||
echo 请选择要运行的测试:
|
||||
echo 1. 快速测试 (推荐)
|
||||
echo 2. 完整测试套件
|
||||
echo 3. 简单连接测试
|
||||
echo 4. 安装依赖
|
||||
echo 5. 退出
|
||||
echo.
|
||||
|
||||
set /p choice=请输入选择 (1-5):
|
||||
|
||||
if "%choice%"=="1" (
|
||||
echo.
|
||||
echo 🚀 运行快速测试...
|
||||
python quick_test.py
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%choice%"=="2" (
|
||||
echo.
|
||||
echo 🚀 运行完整测试套件...
|
||||
python api_client_test.py
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%choice%"=="3" (
|
||||
echo.
|
||||
echo 🚀 运行简单连接测试...
|
||||
python simple_api_test.py
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%choice%"=="4" (
|
||||
echo.
|
||||
echo 📦 安装Python依赖...
|
||||
pip install -r requirements.txt
|
||||
echo 依赖安装完成!
|
||||
goto end
|
||||
)
|
||||
|
||||
if "%choice%"=="5" (
|
||||
echo 👋 再见!
|
||||
goto end
|
||||
)
|
||||
|
||||
echo ❌ 无效选择,请重新运行脚本
|
||||
|
||||
:end
|
||||
echo.
|
||||
pause
|
||||
71
tests/api/run_tests.sh
Normal file
71
tests/api/run_tests.sh
Normal file
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
|
||||
# WhaleTown API 测试工具
|
||||
echo "🐋 WhaleTown API 测试工具"
|
||||
echo "========================"
|
||||
|
||||
# 检查Python是否安装
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
echo "❌ 错误: 未找到 python3,请先安装Python"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 检查是否在正确的目录
|
||||
if [ ! -f "quick_test.py" ]; then
|
||||
echo "❌ 错误: 请在 tests/api 目录下运行此脚本"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "请选择要运行的测试:"
|
||||
echo "1. 快速测试 (推荐)"
|
||||
echo "2. 完整测试套件"
|
||||
echo "3. 简单连接测试"
|
||||
echo "4. 安装依赖"
|
||||
echo "5. 退出"
|
||||
echo ""
|
||||
|
||||
read -p "请输入选择 (1-5): " choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
echo ""
|
||||
echo "🚀 运行快速测试..."
|
||||
python3 quick_test.py
|
||||
;;
|
||||
2)
|
||||
echo ""
|
||||
echo "🚀 运行完整测试套件..."
|
||||
python3 api_client_test.py
|
||||
;;
|
||||
3)
|
||||
echo ""
|
||||
echo "🚀 运行简单连接测试..."
|
||||
python3 simple_api_test.py
|
||||
;;
|
||||
4)
|
||||
echo ""
|
||||
echo "📦 安装Python依赖..."
|
||||
if command -v pip3 &> /dev/null; then
|
||||
pip3 install -r requirements.txt
|
||||
elif command -v pip &> /dev/null; then
|
||||
pip install -r requirements.txt
|
||||
else
|
||||
echo "❌ 错误: 未找到 pip,请手动安装依赖"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ 依赖安装完成!"
|
||||
;;
|
||||
5)
|
||||
echo "👋 再见!"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "❌ 无效选择,请重新运行脚本"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo ""
|
||||
echo "测试完成!按任意键继续..."
|
||||
read -n 1
|
||||
Reference in New Issue
Block a user