acceptance_test.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. #!/usr/bin/env python3
  2. """
  3. AceFlow v2.0 第1阶段验收测试脚本
  4. 全面测试核心功能和用户体验
  5. """
  6. import os
  7. import sys
  8. import json
  9. import yaml
  10. import subprocess
  11. import time
  12. from pathlib import Path
  13. from datetime import datetime
  14. class AceFlowAcceptanceTest:
  15. def __init__(self):
  16. self.project_root = Path.cwd()
  17. self.aceflow_dir = self.project_root / ".aceflow"
  18. self.test_results = []
  19. self.total_tests = 0
  20. self.passed_tests = 0
  21. def log_test(self, test_name, passed, message=""):
  22. """记录测试结果"""
  23. self.total_tests += 1
  24. if passed:
  25. self.passed_tests += 1
  26. status = "✅ PASS"
  27. else:
  28. status = "❌ FAIL"
  29. result = f"{status} {test_name}"
  30. if message:
  31. result += f" - {message}"
  32. self.test_results.append(result)
  33. print(result)
  34. return passed
  35. def run_command(self, command, expect_success=True):
  36. """运行命令并返回结果"""
  37. try:
  38. result = subprocess.run(
  39. command,
  40. shell=True,
  41. capture_output=True,
  42. text=True,
  43. cwd=self.project_root
  44. )
  45. if expect_success:
  46. return result.returncode == 0, result.stdout, result.stderr
  47. else:
  48. return result.returncode != 0, result.stdout, result.stderr
  49. except Exception as e:
  50. return False, "", str(e)
  51. def test_directory_structure(self):
  52. """测试目录结构完整性"""
  53. print("\n🗂️ 测试目录结构...")
  54. required_dirs = [
  55. ".aceflow",
  56. ".aceflow/scripts",
  57. ".aceflow/config",
  58. ".aceflow/templates",
  59. ".aceflow/web",
  60. ".aceflow/state",
  61. ".aceflow/templates/minimal",
  62. ".aceflow/templates/standard"
  63. ]
  64. for dir_path in required_dirs:
  65. path = self.project_root / dir_path
  66. self.log_test(
  67. f"目录存在: {dir_path}",
  68. path.exists() and path.is_dir()
  69. )
  70. def test_core_files(self):
  71. """测试核心文件存在性"""
  72. print("\n📄 测试核心文件...")
  73. required_files = [
  74. ".aceflow/scripts/aceflow",
  75. ".aceflow/scripts/wizard.py",
  76. ".aceflow/config.yaml",
  77. ".aceflow/state/project_state.json",
  78. ".aceflow/config/flow_modes.yaml",
  79. ".aceflow/config/agile_integration.yaml",
  80. ".aceflow/web/index.html",
  81. ".aceflow/templates/minimal/template.yaml",
  82. ".aceflow/templates/minimal/requirements.md",
  83. ".aceflow/templates/minimal/tasks.md",
  84. ".aceflow/templates/standard/template.yaml",
  85. ".clineignore",
  86. ".clinerules/quality_rules.yaml"
  87. ]
  88. for file_path in required_files:
  89. path = self.project_root / file_path
  90. self.log_test(
  91. f"文件存在: {file_path}",
  92. path.exists() and path.is_file()
  93. )
  94. def test_file_permissions(self):
  95. """测试文件权限"""
  96. print("\n🔐 测试文件权限...")
  97. executable_files = [
  98. ".aceflow/scripts/aceflow",
  99. ".aceflow/scripts/wizard.py"
  100. ]
  101. for file_path in executable_files:
  102. path = self.project_root / file_path
  103. if path.exists():
  104. is_executable = os.access(path, os.X_OK)
  105. self.log_test(
  106. f"可执行权限: {file_path}",
  107. is_executable
  108. )
  109. def test_config_files(self):
  110. """测试配置文件格式"""
  111. print("\n⚙️ 测试配置文件...")
  112. # 测试主配置文件
  113. config_file = self.aceflow_dir / "config.yaml"
  114. try:
  115. with open(config_file, 'r', encoding='utf-8') as f:
  116. config = yaml.safe_load(f)
  117. # 检查必需的配置项
  118. required_keys = ['project', 'flow', 'agile', 'ai', 'web']
  119. all_keys_present = all(key in config for key in required_keys)
  120. self.log_test(
  121. "主配置文件格式正确",
  122. all_keys_present,
  123. f"包含所需配置项: {required_keys}"
  124. )
  125. except Exception as e:
  126. self.log_test(
  127. "主配置文件格式正确",
  128. False,
  129. f"解析错误: {e}"
  130. )
  131. # 测试状态文件
  132. state_file = self.aceflow_dir / "state" / "project_state.json"
  133. try:
  134. with open(state_file, 'r', encoding='utf-8') as f:
  135. state = json.load(f)
  136. required_keys = ['project_id', 'flow_mode', 'current_stage', 'stage_states']
  137. all_keys_present = all(key in state for key in required_keys)
  138. self.log_test(
  139. "状态文件格式正确",
  140. all_keys_present,
  141. f"包含所需状态项: {required_keys}"
  142. )
  143. except Exception as e:
  144. self.log_test(
  145. "状态文件格式正确",
  146. False,
  147. f"解析错误: {e}"
  148. )
  149. def test_cli_commands(self):
  150. """测试CLI命令功能"""
  151. print("\n🖥️ 测试CLI命令...")
  152. # 测试help命令
  153. success, stdout, stderr = self.run_command("python3 .aceflow/scripts/aceflow help")
  154. self.log_test(
  155. "help命令正常",
  156. success and "AceFlow v2.0" in stdout
  157. )
  158. # 测试status命令
  159. success, stdout, stderr = self.run_command("python3 .aceflow/scripts/aceflow status")
  160. self.log_test(
  161. "status命令正常",
  162. success and "项目状态" in stdout
  163. )
  164. # 测试start命令(如果还没有活跃阶段)
  165. success, stdout, stderr = self.run_command("python3 .aceflow/scripts/aceflow start")
  166. if "已开始阶段" in stdout or "当前已有活跃阶段" in stdout:
  167. self.log_test("start命令正常", True)
  168. else:
  169. self.log_test("start命令正常", success)
  170. # 测试progress命令
  171. success, stdout, stderr = self.run_command("python3 .aceflow/scripts/aceflow progress --progress 50")
  172. if "进度更新" in stdout or "没有活跃的阶段" in stdout:
  173. self.log_test("progress命令正常", True)
  174. else:
  175. self.log_test("progress命令正常", success)
  176. # 测试web命令
  177. success, stdout, stderr = self.run_command("python3 .aceflow/scripts/aceflow web")
  178. self.log_test(
  179. "web命令正常",
  180. success and ("Web界面已打开" in stdout or "index.html" in stdout)
  181. )
  182. def test_flow_modes(self):
  183. """测试流程模式配置"""
  184. print("\n🔄 测试流程模式...")
  185. flow_config_file = self.aceflow_dir / "config" / "flow_modes.yaml"
  186. try:
  187. with open(flow_config_file, 'r', encoding='utf-8') as f:
  188. flow_config = yaml.safe_load(f)
  189. # 检查三种模式是否都存在
  190. required_modes = ['minimal', 'standard', 'complete']
  191. modes_exist = all(mode in flow_config['flow_modes'] for mode in required_modes)
  192. self.log_test(
  193. "流程模式配置完整",
  194. modes_exist,
  195. f"包含模式: {required_modes}"
  196. )
  197. # 检查轻量级模式的阶段配置
  198. minimal_mode = flow_config['flow_modes']['minimal']
  199. minimal_stages = minimal_mode.get('stages', {})
  200. expected_stages = ['P', 'D', 'R']
  201. stages_correct = all(stage in minimal_stages for stage in expected_stages)
  202. self.log_test(
  203. "轻量级模式阶段正确",
  204. stages_correct,
  205. f"包含阶段: {expected_stages}"
  206. )
  207. except Exception as e:
  208. self.log_test(
  209. "流程模式配置完整",
  210. False,
  211. f"配置错误: {e}"
  212. )
  213. def test_templates(self):
  214. """测试项目模板"""
  215. print("\n📋 测试项目模板...")
  216. # 测试轻量级模板
  217. minimal_template = self.aceflow_dir / "templates" / "minimal" / "template.yaml"
  218. try:
  219. with open(minimal_template, 'r', encoding='utf-8') as f:
  220. template = yaml.safe_load(f)
  221. has_project_config = 'project' in template
  222. has_flow_config = 'flow' in template
  223. has_init_config = 'initialization' in template
  224. self.log_test(
  225. "轻量级模板配置正确",
  226. has_project_config and has_flow_config and has_init_config
  227. )
  228. except Exception as e:
  229. self.log_test(
  230. "轻量级模板配置正确",
  231. False,
  232. f"模板错误: {e}"
  233. )
  234. # 测试模板文档文件
  235. template_docs = [
  236. ".aceflow/templates/minimal/requirements.md",
  237. ".aceflow/templates/minimal/tasks.md"
  238. ]
  239. for doc_file in template_docs:
  240. path = self.project_root / doc_file
  241. content_exists = False
  242. if path.exists():
  243. with open(path, 'r', encoding='utf-8') as f:
  244. content = f.read()
  245. content_exists = len(content.strip()) > 0
  246. self.log_test(
  247. f"模板文档: {Path(doc_file).name}",
  248. content_exists
  249. )
  250. def test_web_interface(self):
  251. """测试Web界面"""
  252. print("\n🌐 测试Web界面...")
  253. web_file = self.aceflow_dir / "web" / "index.html"
  254. if web_file.exists():
  255. with open(web_file, 'r', encoding='utf-8') as f:
  256. content = f.read()
  257. # 检查关键HTML元素
  258. has_title = "AceFlow" in content
  259. has_styles = "<style>" in content
  260. has_scripts = "<script>" in content
  261. has_flow_modes = "flow-modes" in content
  262. has_stages = "stages-container" in content
  263. self.log_test(
  264. "Web界面HTML结构完整",
  265. has_title and has_styles and has_scripts
  266. )
  267. self.log_test(
  268. "Web界面功能组件完整",
  269. has_flow_modes and has_stages
  270. )
  271. # 检查响应式设计
  272. has_responsive = "@media" in content
  273. self.log_test(
  274. "Web界面支持响应式设计",
  275. has_responsive
  276. )
  277. else:
  278. self.log_test("Web界面文件存在", False)
  279. def test_agile_integration(self):
  280. """测试敏捷集成配置"""
  281. print("\n🔄 测试敏捷集成...")
  282. agile_config_file = self.aceflow_dir / "config" / "agile_integration.yaml"
  283. try:
  284. with open(agile_config_file, 'r', encoding='utf-8') as f:
  285. agile_config = yaml.safe_load(f)
  286. # 检查敏捷框架配置
  287. has_scrum = 'scrum' in agile_config.get('agile_frameworks', {})
  288. has_kanban = 'kanban' in agile_config.get('agile_frameworks', {})
  289. has_integration = 'integration_templates' in agile_config
  290. self.log_test(
  291. "敏捷框架配置完整",
  292. has_scrum and has_kanban and has_integration
  293. )
  294. # 检查Scrum配置详细信息
  295. if has_scrum:
  296. scrum_config = agile_config['agile_frameworks']['scrum']
  297. has_ceremonies = 'ceremonies' in scrum_config
  298. has_artifacts = 'artifacts' in scrum_config
  299. has_integration_mapping = 'integration' in scrum_config
  300. self.log_test(
  301. "Scrum配置详细完整",
  302. has_ceremonies and has_artifacts and has_integration_mapping
  303. )
  304. except Exception as e:
  305. self.log_test(
  306. "敏捷集成配置完整",
  307. False,
  308. f"配置错误: {e}"
  309. )
  310. def test_wizard_functionality(self):
  311. """测试快速启动向导"""
  312. print("\n🧙 测试快速启动向导...")
  313. wizard_file = self.aceflow_dir / "scripts" / "wizard.py"
  314. if wizard_file.exists():
  315. # 检查向导脚本的基本结构
  316. with open(wizard_file, 'r', encoding='utf-8') as f:
  317. content = f.read()
  318. has_wizard_class = "class AceFlowWizard" in content
  319. has_main_function = "def main(" in content
  320. has_template_selection = "select_template" in content
  321. has_project_config = "configure_project" in content
  322. self.log_test(
  323. "快速启动向导结构完整",
  324. has_wizard_class and has_main_function
  325. )
  326. self.log_test(
  327. "向导功能模块完整",
  328. has_template_selection and has_project_config
  329. )
  330. # 测试向导脚本语法正确性
  331. success, stdout, stderr = self.run_command("python3 -m py_compile .aceflow/scripts/wizard.py")
  332. self.log_test(
  333. "向导脚本语法正确",
  334. success
  335. )
  336. else:
  337. self.log_test("快速启动向导文件存在", False)
  338. def test_documentation_quality(self):
  339. """测试文档质量"""
  340. print("\n📚 测试文档质量...")
  341. # 检查项目级文档
  342. doc_files = [
  343. "AceFlow_Optimization_Plan.md",
  344. "AceFlow_Migration_Guide.md",
  345. "AceFlow_Quick_Start_Guide.md"
  346. ]
  347. for doc_file in doc_files:
  348. path = self.project_root / doc_file
  349. if path.exists():
  350. with open(path, 'r', encoding='utf-8') as f:
  351. content = f.read()
  352. # 检查文档长度和结构
  353. has_content = len(content) > 1000 # 至少1000字符
  354. has_headers = content.count('#') >= 5 # 至少5个标题
  355. has_chinese = any('\u4e00' <= char <= '\u9fff' for char in content) # 包含中文
  356. self.log_test(
  357. f"文档质量: {doc_file}",
  358. has_content and has_headers and has_chinese
  359. )
  360. else:
  361. self.log_test(f"文档存在: {doc_file}", False)
  362. def test_integration_complete(self):
  363. """测试整体集成完整性"""
  364. print("\n🔗 测试整体集成...")
  365. # 测试从初始化到完成一个完整流程
  366. try:
  367. # 备份当前状态
  368. state_file = self.aceflow_dir / "state" / "project_state.json"
  369. backup_file = self.aceflow_dir / "state" / "project_state_backup.json"
  370. if state_file.exists():
  371. with open(state_file, 'r') as f:
  372. original_state = f.read()
  373. with open(backup_file, 'w') as f:
  374. f.write(original_state)
  375. # 测试完整工作流
  376. workflow_success = True
  377. # 1. 开始阶段
  378. success, stdout, stderr = self.run_command("python3 .aceflow/scripts/aceflow start P")
  379. if not success and "当前已有活跃阶段" not in stdout:
  380. workflow_success = False
  381. # 2. 更新进度
  382. success, stdout, stderr = self.run_command("python3 .aceflow/scripts/aceflow progress --progress 100")
  383. if not success and "进度更新" not in stdout:
  384. workflow_success = False
  385. # 3. 完成阶段
  386. success, stdout, stderr = self.run_command("python3 .aceflow/scripts/aceflow complete")
  387. if not success and "完成阶段" not in stdout:
  388. workflow_success = False
  389. self.log_test(
  390. "完整工作流测试",
  391. workflow_success
  392. )
  393. # 恢复原始状态
  394. if backup_file.exists():
  395. with open(backup_file, 'r') as f:
  396. original_state = f.read()
  397. with open(state_file, 'w') as f:
  398. f.write(original_state)
  399. backup_file.unlink()
  400. except Exception as e:
  401. self.log_test(
  402. "完整工作流测试",
  403. False,
  404. f"测试错误: {e}"
  405. )
  406. def run_all_tests(self):
  407. """运行所有测试"""
  408. print("🧪 开始AceFlow v2.0第1阶段验收测试")
  409. print("=" * 60)
  410. start_time = time.time()
  411. # 运行所有测试
  412. self.test_directory_structure()
  413. self.test_core_files()
  414. self.test_file_permissions()
  415. self.test_config_files()
  416. self.test_cli_commands()
  417. self.test_flow_modes()
  418. self.test_templates()
  419. self.test_web_interface()
  420. self.test_agile_integration()
  421. self.test_wizard_functionality()
  422. self.test_documentation_quality()
  423. self.test_integration_complete()
  424. end_time = time.time()
  425. duration = end_time - start_time
  426. # 生成测试报告
  427. self.generate_report(duration)
  428. def generate_report(self, duration):
  429. """生成测试报告"""
  430. print("\n" + "=" * 60)
  431. print("📊 验收测试报告")
  432. print("=" * 60)
  433. success_rate = (self.passed_tests / self.total_tests) * 100 if self.total_tests > 0 else 0
  434. print(f"📈 测试统计:")
  435. print(f" 总测试数: {self.total_tests}")
  436. print(f" 通过测试: {self.passed_tests}")
  437. print(f" 失败测试: {self.total_tests - self.passed_tests}")
  438. print(f" 成功率: {success_rate:.1f}%")
  439. print(f" 测试耗时: {duration:.2f}秒")
  440. print(f"\n📋 详细结果:")
  441. for result in self.test_results:
  442. print(f" {result}")
  443. # 总体评估
  444. print(f"\n🎯 验收结果:")
  445. if success_rate >= 90:
  446. print(" 🎉 验收通过 - 第1阶段开发目标已达成")
  447. print(" ✨ 系统功能完整,质量良好,可以进入第2阶段")
  448. elif success_rate >= 80:
  449. print(" ⚠️ 有条件通过 - 存在少量问题需要修复")
  450. print(" 🔧 建议修复失败项后再进入下一阶段")
  451. else:
  452. print(" ❌ 验收未通过 - 存在重大问题需要解决")
  453. print(" 🛠️ 需要重点修复失败项目")
  454. # 保存报告
  455. self.save_report(duration, success_rate)
  456. def save_report(self, duration, success_rate):
  457. """保存测试报告到文件"""
  458. report_data = {
  459. "test_time": datetime.now().isoformat(),
  460. "duration_seconds": duration,
  461. "total_tests": self.total_tests,
  462. "passed_tests": self.passed_tests,
  463. "failed_tests": self.total_tests - self.passed_tests,
  464. "success_rate": success_rate,
  465. "test_results": self.test_results,
  466. "stage": "第1阶段验收测试",
  467. "version": "AceFlow v2.0"
  468. }
  469. # 创建报告目录
  470. reports_dir = self.aceflow_dir / "reports"
  471. reports_dir.mkdir(exist_ok=True)
  472. # 保存JSON格式报告
  473. report_file = reports_dir / f"acceptance_test_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
  474. with open(report_file, 'w', encoding='utf-8') as f:
  475. json.dump(report_data, f, indent=2, ensure_ascii=False)
  476. print(f"\n💾 测试报告已保存: {report_file}")
  477. def main():
  478. """主函数"""
  479. print("🚀 AceFlow v2.0 第1阶段验收测试")
  480. print("测试AI驱动的敏捷开发工作流框架核心功能")
  481. print()
  482. # 检查是否在正确的项目目录
  483. aceflow_dir = Path(".aceflow")
  484. if not aceflow_dir.exists():
  485. print("❌ 错误: 当前目录不是AceFlow项目目录")
  486. print("请在包含.aceflow目录的项目根目录下运行此脚本")
  487. sys.exit(1)
  488. # 运行测试
  489. tester = AceFlowAcceptanceTest()
  490. tester.run_all_tests()
  491. if __name__ == "__main__":
  492. main()