run_regression.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. from __future__ import annotations
  2. """TravelMind自动回归测试入口:依次运行全部本地单元测试,可选运行调用真实模型和外部API的集成测试。"""
  3. import argparse
  4. import subprocess
  5. import sys
  6. from dataclasses import dataclass
  7. @dataclass(frozen=True)
  8. class TestCommand:
  9. name: str
  10. args: list[str]
  11. UNIT_TESTS = [
  12. TestCommand(
  13. name="所有本地单元测试",
  14. args=[
  15. sys.executable,
  16. "-m",
  17. "pytest",
  18. "tests",
  19. "-v",
  20. ],
  21. ),
  22. ]
  23. INTEGRATION_TESTS = [
  24. TestCommand(
  25. name="MCP工具注册",
  26. args=[
  27. sys.executable,
  28. "-m",
  29. "scripts.test_mcp_registry",
  30. ],
  31. ),
  32. TestCommand(
  33. name="需求解析Graph",
  34. args=[
  35. sys.executable,
  36. "-m",
  37. "scripts.test_requirement_graph",
  38. ],
  39. ),
  40. TestCommand(
  41. name="资源查询Graph",
  42. args=[
  43. sys.executable,
  44. "-m",
  45. "scripts.test_resource_graph",
  46. ],
  47. ),
  48. TestCommand(
  49. name="地图研究Graph",
  50. args=[
  51. sys.executable,
  52. "-m",
  53. "scripts.test_research_graph",
  54. ],
  55. ),
  56. TestCommand(
  57. name="候选筛选Graph",
  58. args=[
  59. sys.executable,
  60. "-m",
  61. "scripts.test_selection_graph",
  62. ],
  63. ),
  64. TestCommand(
  65. name="路线评估Graph",
  66. args=[
  67. sys.executable,
  68. "-m",
  69. "scripts.test_route_graph",
  70. ],
  71. ),
  72. TestCommand(
  73. name="最终多角色Graph",
  74. args=[
  75. sys.executable,
  76. "-m",
  77. "scripts.test_final_graph",
  78. ],
  79. ),
  80. ]
  81. def run_command(
  82. command: TestCommand,
  83. ) -> bool:
  84. """以子进程方式执行单个TestCommand,输出分隔线与结果。"""
  85. separator = "=" * 72
  86. print()
  87. print(separator)
  88. print(f"开始:{command.name}")
  89. print(separator)
  90. completed = subprocess.run(
  91. command.args,
  92. check=False,
  93. )
  94. if completed.returncode == 0:
  95. print(f"通过:{command.name}")
  96. return True
  97. print(
  98. f"失败:{command.name},"
  99. f"returncode={completed.returncode}"
  100. )
  101. return False
  102. def parse_args() -> argparse.Namespace:
  103. """解析命令行参数:--integration启用集成测试,--continue-on-error在单项失败后继续。"""
  104. parser = argparse.ArgumentParser(
  105. description=(
  106. "运行TravelMind自动回归测试。"
  107. )
  108. )
  109. parser.add_argument(
  110. "--integration",
  111. action="store_true",
  112. help=(
  113. "同时运行会调用真实模型、SerpApi"
  114. "和高德MCP的集成测试。"
  115. ),
  116. )
  117. parser.add_argument(
  118. "--continue-on-error",
  119. action="store_true",
  120. help="单项失败后继续执行后续测试。",
  121. )
  122. return parser.parse_args()
  123. def main() -> None:
  124. """依次执行全部测试命令,汇总失败项并以非零退出码结束。"""
  125. args = parse_args()
  126. commands = list(UNIT_TESTS)
  127. if args.integration:
  128. commands.extend(INTEGRATION_TESTS)
  129. failed_commands: list[str] = []
  130. for command in commands:
  131. passed = run_command(command)
  132. if passed:
  133. continue
  134. failed_commands.append(command.name)
  135. if not args.continue_on_error:
  136. break
  137. print()
  138. print("=" * 72)
  139. if failed_commands:
  140. print("回归测试未通过:")
  141. for name in failed_commands:
  142. print(f"- {name}")
  143. raise SystemExit(1)
  144. print("全部回归测试通过。")
  145. if __name__ == "__main__":
  146. main()