refactor: 优化网络请求和错误处理 fix: 修复颜色引用和UI细节问题 docs: 更新API文档和设计规范 chore: 清理无用文件和脚本 perf: 优化图片导出和压缩逻辑 build: 更新依赖和构建配置 style: 调整代码格式和注释 test: 添加接口验证脚本 ci: 更新CI配置和脚本
313 lines
10 KiB
Python
313 lines
10 KiB
Python
"""
|
||
============================================================
|
||
闲言APP — 全量API接口测试脚本
|
||
创建时间: 2026-04-28
|
||
更新时间: 2026-04-28
|
||
作用: 模拟用户注册登录,测试所有API接口
|
||
上次更新: 增加收藏、笔记、签到、统计、纠错接口测试
|
||
============================================================
|
||
"""
|
||
|
||
import requests
|
||
import json
|
||
import time
|
||
import random
|
||
import string
|
||
|
||
BASE_URL = "https://tools.wktyl.com"
|
||
TIMEOUT = 15
|
||
|
||
TEST_ACCOUNT = f"testbot_{''.join(random.choices(string.digits, k=4))}"
|
||
TEST_PASSWORD = "Test123456"
|
||
TEST_EMAIL = f"{TEST_ACCOUNT}@test.local"
|
||
|
||
token = None
|
||
user_id = None
|
||
|
||
|
||
def log_test(name, success, detail=""):
|
||
status = "✅" if success else "❌"
|
||
print(f" {status} {name}" + (f" — {detail}" if detail else ""))
|
||
|
||
|
||
def api_get(path, params=None, use_token=True):
|
||
headers = {}
|
||
if use_token and token:
|
||
headers["token"] = token
|
||
try:
|
||
r = requests.get(f"{BASE_URL}{path}", params=params, headers=headers, timeout=TIMEOUT)
|
||
return r.json()
|
||
except Exception as e:
|
||
return {"code": -999, "msg": str(e)}
|
||
|
||
|
||
def api_post(path, data=None, use_token=True):
|
||
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
||
if use_token and token:
|
||
headers["token"] = token
|
||
try:
|
||
r = requests.post(f"{BASE_URL}{path}", data=data, headers=headers, timeout=TIMEOUT)
|
||
return r.json()
|
||
except Exception as e:
|
||
return {"code": -999, "msg": str(e)}
|
||
|
||
|
||
def test_auth():
|
||
global token, user_id
|
||
print("\n🔐 认证模块测试")
|
||
print("-" * 40)
|
||
|
||
data = api_post("/api/user/register", data={
|
||
"username": TEST_ACCOUNT,
|
||
"password": TEST_PASSWORD,
|
||
"email": TEST_EMAIL,
|
||
}, use_token=False)
|
||
reg_ok = data.get("code") in [1, 0]
|
||
log_test("用户注册", reg_ok, f"code={data.get('code')}, msg={data.get('msg', '')[:30]}")
|
||
|
||
data = api_post("/api/user/login", data={
|
||
"account": TEST_ACCOUNT,
|
||
"password": TEST_PASSWORD,
|
||
}, use_token=False)
|
||
login_ok = data.get("code") == 1
|
||
log_test("用户登录", login_ok, f"code={data.get('code')}")
|
||
if login_ok:
|
||
userinfo = data.get("data", {}).get("userinfo", {})
|
||
token = userinfo.get("token", "")
|
||
user_id = userinfo.get("id", 0)
|
||
print(f" 📌 token={token[:20]}... user_id={user_id}")
|
||
|
||
data = api_get("/api/user/index")
|
||
log_test("获取用户信息", data.get("code") == 1, f"nickname={data.get('data', {}).get('nickname', 'N/A')}")
|
||
|
||
data = api_post("/api/user/tokenLogin", use_token=True)
|
||
log_test("Token自动登录", data.get("code") == 1)
|
||
|
||
data = api_get("/api/user/index", use_token=False)
|
||
log_test("未登录访问用户信息", data.get("code") in [0, -1, 401])
|
||
|
||
|
||
def test_signin():
|
||
print("\n📅 签到模块测试")
|
||
print("-" * 40)
|
||
|
||
data = api_post("/api/user/signin")
|
||
log_test("每日签到", data.get("code") in [1, 0], f"msg={data.get('msg', '')[:30]}")
|
||
|
||
data = api_post("/api/user/signin")
|
||
log_test("重复签到", data.get("code") == 0, f"msg={data.get('msg', '')[:30]}")
|
||
|
||
|
||
def test_favorite():
|
||
print("\n💕 收藏模块测试")
|
||
print("-" * 40)
|
||
|
||
data = api_post("/api/user/favorite", data={
|
||
"action": "add",
|
||
"target_type": "article",
|
||
"target_id": 1,
|
||
})
|
||
log_test("添加收藏", data.get("code") == 1, f"msg={data.get('msg', '')[:30]}")
|
||
|
||
data = api_post("/api/user/favorite", data={
|
||
"action": "check",
|
||
"target_type": "article",
|
||
"target_id": 1,
|
||
})
|
||
is_fav = (data.get("data") or {}).get("is_favorited", False)
|
||
log_test("检查收藏状态", data.get("code") == 1, f"is_favorited={is_fav}")
|
||
|
||
data = api_get("/api/user/favorite", params={
|
||
"action": "list",
|
||
"target_type": "article",
|
||
"page": 1,
|
||
"limit": 10,
|
||
})
|
||
fav_data = data.get("data") or {}
|
||
total = fav_data.get("total", "N/A")
|
||
log_test("收藏列表", data.get("code") == 1, f"total={total}")
|
||
|
||
data = api_post("/api/user/favorite", data={
|
||
"action": "remove",
|
||
"target_type": "article",
|
||
"target_id": 1,
|
||
})
|
||
log_test("取消收藏", data.get("code") == 1, f"msg={data.get('msg', '')[:30]}")
|
||
|
||
data = api_post("/api/user/favorite", data={
|
||
"action": "check",
|
||
"target_type": "article",
|
||
"target_id": 1,
|
||
})
|
||
is_fav2 = (data.get("data") or {}).get("is_favorited", True)
|
||
log_test("取消后检查", not is_fav2, f"is_favorited={is_fav2}")
|
||
|
||
|
||
def test_note():
|
||
print("\n📝 笔记模块测试")
|
||
print("-" * 40)
|
||
|
||
data = api_post("/api/user/note", data={
|
||
"action": "add",
|
||
"title": f"测试笔记_{int(time.time())}",
|
||
"content": "这是一条自动测试创建的笔记内容,用于验证笔记接口功能。",
|
||
"category": "测试",
|
||
})
|
||
log_test("添加笔记", data.get("code") == 1, f"msg={data.get('msg', '')[:30]}")
|
||
|
||
data = api_get("/api/user/note", params={
|
||
"action": "list",
|
||
"page": 1,
|
||
"limit": 10,
|
||
})
|
||
note_data = data.get("data") or {}
|
||
notes = note_data.get("list") or []
|
||
total = note_data.get("total", "N/A")
|
||
note_id = notes[0].get("id", 0) if notes else 0
|
||
log_test("笔记列表", data.get("code") == 1, f"total={total}, first_id={note_id}")
|
||
|
||
if note_id:
|
||
data = api_post("/api/user/note", data={
|
||
"action": "edit",
|
||
"id": note_id,
|
||
"title": f"编辑后的笔记_{int(time.time())}",
|
||
"content": "这是编辑后的笔记内容。",
|
||
})
|
||
log_test("编辑笔记", data.get("code") == 1, f"msg={data.get('msg', '')[:30]}")
|
||
|
||
data = api_post("/api/user/note", data={
|
||
"action": "delete",
|
||
"id": note_id,
|
||
})
|
||
log_test("删除笔记", data.get("code") == 1, f"msg={data.get('msg', '')[:30]}")
|
||
else:
|
||
log_test("编辑笔记", False, "无笔记可编辑")
|
||
log_test("删除笔记", False, "无笔记可删除")
|
||
|
||
|
||
def test_statistics():
|
||
print("\n📊 统计模块测试")
|
||
print("-" * 40)
|
||
|
||
data = api_get("/api/statistics/overview", use_token=False)
|
||
log_test("站点总览", data.get("code") == 1, f"users={data.get('data', {}).get('total_users', 'N/A')}")
|
||
|
||
data = api_get("/api/statistics/users", use_token=False)
|
||
log_test("用户统计", data.get("code") == 1, f"total={data.get('data', {}).get('total', 'N/A')}")
|
||
|
||
data = api_get("/api/statistics/signins", use_token=False)
|
||
log_test("签到统计", data.get("code") == 1, f"total={data.get('data', {}).get('total', 'N/A')}")
|
||
|
||
data = api_get("/api/statistics/coins", use_token=False)
|
||
log_test("金币统计", data.get("code") == 1, f"total_score={data.get('data', {}).get('total_score', 'N/A')}")
|
||
|
||
data = api_get("/api/statistics/notes", use_token=False)
|
||
log_test("笔记统计", data.get("code") == 1, f"total={data.get('data', {}).get('total', 'N/A')}")
|
||
|
||
|
||
def test_search():
|
||
print("\n🔍 搜索模块测试")
|
||
print("-" * 40)
|
||
|
||
data = api_get("/api/search/index", params={
|
||
"keyword": "人",
|
||
"type": "all",
|
||
"mode": "fuzzy",
|
||
}, use_token=False)
|
||
log_test("综合搜索", data.get("code") == 1, f"keyword={data.get('data', {}).get('keyword', 'N/A')}")
|
||
|
||
data = api_get("/api/search/index", params={
|
||
"keyword": "中",
|
||
"type": "hanzi",
|
||
"mode": "exact",
|
||
}, use_token=False)
|
||
hanzi_data = data.get("data") or {}
|
||
hanzi_total = (hanzi_data.get("results") or {}).get("hanzi", {}).get("total", "N/A")
|
||
log_test("汉字搜索", data.get("code") == 1, f"hanzi_total={hanzi_total}")
|
||
|
||
data = api_get("/api/search/index", params={
|
||
"keyword": "一心",
|
||
"type": "cy",
|
||
"mode": "fuzzy",
|
||
}, use_token=False)
|
||
log_test("成语搜索", data.get("code") == 1)
|
||
|
||
data = api_get("/api/search/index", params={
|
||
"keyword": "静夜思",
|
||
"type": "poetry",
|
||
"mode": "exact",
|
||
}, use_token=False)
|
||
log_test("诗词搜索", data.get("code") == 1)
|
||
|
||
data = api_get("/api/search/index", params={
|
||
"keyword": "",
|
||
"type": "all",
|
||
}, use_token=False)
|
||
log_test("空关键词搜索", data.get("code") in [0, 1], f"msg={data.get('msg', '')[:30]}")
|
||
|
||
|
||
def test_correction():
|
||
print("\n🔍 纠错模块测试")
|
||
print("-" * 40)
|
||
|
||
data = api_post("/api/webapi/correction_submit", data={
|
||
"content": f"自动测试纠错内容_{int(time.time())}:此条为接口测试数据,可忽略。",
|
||
"mail": TEST_EMAIL,
|
||
"source_url": "https://tools.wktyl.com/hanzi/1",
|
||
}, use_token=False)
|
||
log_test("提交纠错", data.get("code") == 1, f"msg={data.get('msg', '')[:30]}")
|
||
|
||
|
||
def test_webapi():
|
||
print("\n🌐 WebAPI模块测试")
|
||
print("-" * 40)
|
||
|
||
data = api_get("/api/webapi/hitokoto", use_token=False)
|
||
log_test("一言接口", data.get("code") == 1 or "hitokoto" in str(data)[:100])
|
||
|
||
data = api_get("/api/webapi/moyu", use_token=False)
|
||
log_test("摸鱼接口", data.get("code") == 1 or "moyu" in str(data)[:100] or data.get("data") is not None)
|
||
|
||
|
||
def test_profile():
|
||
print("\n👤 个人信息模块测试")
|
||
print("-" * 40)
|
||
|
||
data = api_post("/api/user/profile", data={
|
||
"nickname": f"测试昵称_{int(time.time())}",
|
||
"bio": "这是自动测试修改的个人简介",
|
||
})
|
||
log_test("修改个人信息", data.get("code") == 1, f"msg={data.get('msg', '')[:30]}")
|
||
|
||
data = api_get("/api/user/index")
|
||
nickname = data.get("data", {}).get("nickname", "N/A")
|
||
log_test("验证修改结果", data.get("code") == 1, f"nickname={nickname}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
print("=" * 50)
|
||
print("🚀 闲言APP — 全量API接口测试")
|
||
print(f" 时间: {time.strftime('%Y-%m-%d %H:%M:%S')}")
|
||
print(f" 测试账号: {TEST_ACCOUNT}")
|
||
print("=" * 50)
|
||
|
||
try:
|
||
test_auth()
|
||
if token:
|
||
test_signin()
|
||
test_favorite()
|
||
test_note()
|
||
test_profile()
|
||
test_statistics()
|
||
test_search()
|
||
test_correction()
|
||
test_webapi()
|
||
except Exception as e:
|
||
print(f"\n💥 测试中断: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
|
||
print("\n" + "=" * 50)
|
||
print("🏁 测试完成!")
|
||
print("=" * 50)
|