test_api_design.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #!/usr/bin/env python3
  2. """
  3. 测试修改后的 API 是否符合设计文档要求
  4. """
  5. import json
  6. import asyncio
  7. import aiohttp
  8. from typing import Dict, Any
  9. async def test_api_design_compliance():
  10. """测试 API 设计文档合规性"""
  11. base_url = "http://localhost:8000"
  12. # 测试用例
  13. test_cases = [
  14. {
  15. "name": "基本聊天测试",
  16. "payload": {
  17. "question": "你好,我想了解一下今天的天气",
  18. "user_id": "wang"
  19. },
  20. "expected_fields": ["response", "react_agent_meta", "timestamp"]
  21. },
  22. {
  23. "name": "SQL查询测试",
  24. "payload": {
  25. "question": "请查询服务区的收入数据",
  26. "user_id": "test_user"
  27. },
  28. "expected_fields": ["response", "sql", "records", "react_agent_meta", "timestamp"]
  29. },
  30. {
  31. "name": "继续对话测试",
  32. "payload": {
  33. "question": "请详细说明一下",
  34. "user_id": "wang",
  35. "thread_id": None # 将在第一个测试后设置
  36. },
  37. "expected_fields": ["response", "react_agent_meta", "timestamp"]
  38. }
  39. ]
  40. session = aiohttp.ClientSession()
  41. try:
  42. print("🧪 开始测试 API 设计文档合规性...")
  43. print("=" * 60)
  44. thread_id = None
  45. for i, test_case in enumerate(test_cases, 1):
  46. print(f"\n📋 测试 {i}: {test_case['name']}")
  47. print("-" * 40)
  48. # 如果是继续对话测试,使用之前的 thread_id
  49. if test_case["name"] == "继续对话测试" and thread_id:
  50. test_case["payload"]["thread_id"] = thread_id
  51. # 发送请求
  52. async with session.post(
  53. f"{base_url}/api/chat",
  54. json=test_case["payload"],
  55. headers={"Content-Type": "application/json"}
  56. ) as response:
  57. print(f"📊 HTTP状态码: {response.status}")
  58. if response.status != 200:
  59. print(f"❌ 请求失败,状态码: {response.status}")
  60. continue
  61. # 解析响应
  62. result = await response.json()
  63. # 验证顶级结构
  64. required_top_fields = ["code", "message", "success", "data"]
  65. for field in required_top_fields:
  66. if field not in result:
  67. print(f"❌ 缺少顶级字段: {field}")
  68. else:
  69. print(f"✅ 顶级字段 {field}: {result[field]}")
  70. # 验证 data 字段结构
  71. if "data" in result:
  72. data = result["data"]
  73. print(f"\n📦 data 字段包含: {list(data.keys())}")
  74. # 验证必需字段
  75. required_fields = ["response", "react_agent_meta", "timestamp"]
  76. for field in required_fields:
  77. if field not in data:
  78. print(f"❌ data 中缺少必需字段: {field}")
  79. else:
  80. print(f"✅ 必需字段 {field}: 存在")
  81. # 验证可选字段
  82. optional_fields = ["sql", "records"]
  83. for field in optional_fields:
  84. if field in data:
  85. print(f"✅ 可选字段 {field}: 存在")
  86. else:
  87. print(f"ℹ️ 可选字段 {field}: 不存在(正常)")
  88. # 验证 react_agent_meta 结构
  89. if "react_agent_meta" in data:
  90. meta = data["react_agent_meta"]
  91. print(f"\n🔧 react_agent_meta 字段: {list(meta.keys())}")
  92. # 保存 thread_id 用于后续测试
  93. if "thread_id" in meta:
  94. thread_id = meta["thread_id"]
  95. print(f"🆔 Thread ID: {thread_id}")
  96. # 验证 records 结构(如果存在)
  97. if "records" in data:
  98. records = data["records"]
  99. print(f"\n📊 records 字段: {list(records.keys())}")
  100. required_record_fields = ["columns", "rows", "total_row_count", "is_limited"]
  101. for field in required_record_fields:
  102. if field not in records:
  103. print(f"❌ records 中缺少字段: {field}")
  104. else:
  105. print(f"✅ records 字段 {field}: 存在")
  106. print(f"\n✅ 测试 {i} 完成")
  107. print("\n" + "=" * 60)
  108. print("🎉 所有测试完成!")
  109. except Exception as e:
  110. print(f"❌ 测试过程中发生错误: {e}")
  111. import traceback
  112. traceback.print_exc()
  113. finally:
  114. await session.close()
  115. async def test_error_handling():
  116. """测试错误处理"""
  117. base_url = "http://localhost:8000"
  118. session = aiohttp.ClientSession()
  119. try:
  120. print("\n🧪 测试错误处理...")
  121. print("=" * 60)
  122. # 测试参数错误
  123. test_cases = [
  124. {
  125. "name": "缺少问题",
  126. "payload": {"user_id": "test"},
  127. "expected_code": 400
  128. },
  129. {
  130. "name": "空问题",
  131. "payload": {"question": "", "user_id": "test"},
  132. "expected_code": 400
  133. },
  134. {
  135. "name": "问题过长",
  136. "payload": {"question": "x" * 2001, "user_id": "test"},
  137. "expected_code": 400
  138. }
  139. ]
  140. for test_case in test_cases:
  141. print(f"\n📋 错误测试: {test_case['name']}")
  142. async with session.post(
  143. f"{base_url}/api/chat",
  144. json=test_case["payload"],
  145. headers={"Content-Type": "application/json"}
  146. ) as response:
  147. result = await response.json()
  148. print(f"📊 HTTP状态码: {response.status}")
  149. print(f"📋 响应代码: {result.get('code')}")
  150. print(f"🎯 成功状态: {result.get('success')}")
  151. print(f"❌ 错误信息: {result.get('error')}")
  152. if response.status == test_case["expected_code"]:
  153. print("✅ 错误处理正确")
  154. else:
  155. print(f"❌ 期望状态码 {test_case['expected_code']}, 实际 {response.status}")
  156. finally:
  157. await session.close()
  158. if __name__ == "__main__":
  159. print("🚀 启动 API 设计文档合规性测试")
  160. print("请确保 API 服务已启动 (python api.py)")
  161. print("=" * 60)
  162. asyncio.run(test_api_design_compliance())
  163. asyncio.run(test_error_handling())