main.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. """
  2. 智能API测试助手 - 命令行入口
  3. 把五个 Agent 串成完整流程:
  4. 解析 → 生成 → 执行 → 验证 → 报告
  5. """
  6. import sys
  7. # Windows 中文控制台默认是 GBK,先重配为 UTF-8,否则打印中文会崩
  8. if hasattr(sys.stdout, "reconfigure"):
  9. sys.stdout.reconfigure(encoding="utf-8", errors="replace")
  10. sys.stderr.reconfigure(encoding="utf-8", errors="replace")
  11. import argparse
  12. from dotenv import load_dotenv
  13. # 关键:先加载 .env,再 import Agent(Agent 实例化时要读环境变量)
  14. load_dotenv()
  15. from src.agents.parser_agent import ParserAgent
  16. from src.agents.generator_agent import GeneratorAgent
  17. from src.agents.executor_agent import ExecutorAgent
  18. from src.agents.validator_agent import ValidatorAgent
  19. from src.agents.reporter_agent import ReporterAgent
  20. from src.config import REPORT_OUTPUT_DIR
  21. def run_test(base_url, openapi_file=None, openapi_url=None, headers=None):
  22. """执行完整的 API 测试流程
  23. Args:
  24. base_url: 目标 API 的基础地址
  25. openapi_file: OpenAPI 文档路径(本地文件)
  26. openapi_url: OpenAPI 文档网址(从网络抓取),与 file 二选一
  27. headers: 全局请求头(可选),如认证信息
  28. Returns:
  29. 报告文件的保存路径
  30. """
  31. print("=" * 50)
  32. print("开始 API 测试流程")
  33. print("=" * 50)
  34. # ① 解析文档(优先用 URL,否则用本地文件)
  35. parser = ParserAgent()
  36. if openapi_url:
  37. endpoints = parser.parse_url(openapi_url)
  38. else:
  39. endpoints = parser.parse_file(openapi_file)
  40. # 没有解析出任何接口,说明文档抓取/解析失败,直接退出
  41. if not endpoints:
  42. print("❌ 未能解析出任何接口,请检查文档地址或内容是否正确")
  43. return None
  44. print(f"[1/5] 解析完成:发现 {len(endpoints)} 个接口")
  45. # ② 生成用例(每个接口都生成,用 extend 合并成一个大列表)
  46. generator = GeneratorAgent()
  47. all_cases = []
  48. for endpoint in endpoints:
  49. cases = generator.generate(endpoint)
  50. all_cases.extend(cases)
  51. print(f"[2/5] 生成完成:共 {len(all_cases)} 个测试用例")
  52. # ③ 执行测试(传入认证头)
  53. executor = ExecutorAgent()
  54. execution_results = executor.execute(all_cases, base_url, headers=headers)
  55. print(f"[3/5] 执行完成:已发送 {len(execution_results)} 个请求")
  56. # ④ 验证结果
  57. validator = ValidatorAgent()
  58. validated_results = validator.validate(execution_results)
  59. print(f"[4/5] 验证完成")
  60. # ⑤ 生成并保存报告(HTML + Markdown 两种格式)
  61. reporter = ReporterAgent()
  62. summary = reporter.summarize(validated_results)
  63. html = reporter.generate_html(validated_results)
  64. markdown = reporter.generate_markdown(validated_results)
  65. import os
  66. os.makedirs(REPORT_OUTPUT_DIR, exist_ok=True)
  67. html_path = os.path.join(REPORT_OUTPUT_DIR, "report.html")
  68. md_path = os.path.join(REPORT_OUTPUT_DIR, "report.md")
  69. with open(html_path, "w", encoding="utf-8") as f:
  70. f.write(html)
  71. with open(md_path, "w", encoding="utf-8") as f:
  72. f.write(markdown)
  73. print(f"[5/5] 报告已生成:{html_path} 和 {md_path}")
  74. print("=" * 50)
  75. print(f"测试结果:总数 {summary['total']},"
  76. f"通过 {summary['passed']},失败 {summary['failed']},"
  77. f"通过率 {summary['pass_rate']}%")
  78. print("=" * 50)
  79. return html_path
  80. def main():
  81. # 解析命令行参数
  82. parser = argparse.ArgumentParser(description="智能API测试助手")
  83. parser.add_argument("--file", help="OpenAPI 文档路径(本地文件)")
  84. parser.add_argument("--url", help="OpenAPI 文档网址(从网络抓取)")
  85. parser.add_argument("--base-url", required=True, help="目标 API 基础地址")
  86. parser.add_argument("--header", action="append",
  87. help="自定义请求头,格式 'Key: Value',可多次使用,如 --header 'Authorization: Bearer xxx'")
  88. args = parser.parse_args()
  89. # --file 和 --url 必须二选一
  90. if not args.file and not args.url:
  91. parser.error("必须提供 --file 或 --url 之一")
  92. if args.file and args.url:
  93. parser.error("--file 和 --url 只能选一个")
  94. # 解析请求头 "Key: Value" → dict
  95. headers = {}
  96. if args.header:
  97. for h in args.header:
  98. if ":" in h:
  99. key, value = h.split(":", 1)
  100. headers[key.strip()] = value.strip()
  101. else:
  102. parser.error(f"请求头格式错误(应为 'Key: Value'):{h}")
  103. run_test(base_url=args.base_url, openapi_file=args.file,
  104. openapi_url=args.url, headers=headers)
  105. if __name__ == "__main__":
  106. main()