run_tests.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. AI驱动软件著作权申请材料生成系统 - 自动化测试脚本
  5. 版本: 1.0
  6. 描述: 快速验证系统核心功能和集成测试
  7. """
  8. import os
  9. import sys
  10. import subprocess
  11. import tempfile
  12. import shutil
  13. from pathlib import Path
  14. import json
  15. import time
  16. class Colors:
  17. """终端颜色定义"""
  18. RED = '\033[0;31m'
  19. GREEN = '\033[0;32m'
  20. YELLOW = '\033[1;33m'
  21. BLUE = '\033[0;34m'
  22. PURPLE = '\033[0;35m'
  23. CYAN = '\033[0;36m'
  24. NC = '\033[0m'
  25. class TestRunner:
  26. """测试运行器"""
  27. def __init__(self, project_dir: Path):
  28. self.project_dir = project_dir
  29. self.test_results = []
  30. def print_colored(self, color: str, message: str):
  31. """打印带颜色的消息"""
  32. print(f"{color}{message}{Colors.NC}")
  33. def print_header(self, title: str):
  34. """打印测试章节标题"""
  35. self.print_colored(Colors.CYAN, f"\n{'='*60}")
  36. self.print_colored(Colors.CYAN, f"🧪 {title}")
  37. self.print_colored(Colors.CYAN, f"{'='*60}")
  38. def run_test(self, test_name: str, test_func):
  39. """运行单个测试"""
  40. self.print_colored(Colors.BLUE, f"🔄 运行测试: {test_name}")
  41. start_time = time.time()
  42. try:
  43. result = test_func()
  44. duration = time.time() - start_time
  45. if result:
  46. self.print_colored(Colors.GREEN, f"✅ 测试通过: {test_name} ({duration:.2f}s)")
  47. self.test_results.append({"name": test_name, "status": "PASS", "duration": duration})
  48. return True
  49. else:
  50. self.print_colored(Colors.RED, f"❌ 测试失败: {test_name} ({duration:.2f}s)")
  51. self.test_results.append({"name": test_name, "status": "FAIL", "duration": duration})
  52. return False
  53. except Exception as e:
  54. duration = time.time() - start_time
  55. self.print_colored(Colors.RED, f"💥 测试异常: {test_name} - {e} ({duration:.2f}s)")
  56. self.test_results.append({"name": test_name, "status": "ERROR", "duration": duration, "error": str(e)})
  57. return False
  58. def test_project_structure(self):
  59. """测试项目结构完整性"""
  60. required_files = [
  61. "ai-copyright-config.json",
  62. "scripts/init/init_project.py",
  63. "scripts/validators/check_project.py",
  64. "README.md",
  65. "ai-copyright.py",
  66. "ai-copyright.sh"
  67. ]
  68. required_dirs = [
  69. "specs_docs",
  70. "system_prompts",
  71. "requires_docs"
  72. ]
  73. for file_path in required_files:
  74. if not (self.project_dir / file_path).exists():
  75. return False
  76. for dir_path in required_dirs:
  77. if not (self.project_dir / dir_path).is_dir():
  78. return False
  79. return True
  80. def test_config_file_validity(self):
  81. """测试配置文件有效性"""
  82. config_path = self.project_dir / "ai-copyright-config.json"
  83. if not config_path.exists():
  84. return False
  85. try:
  86. with open(config_path, 'r', encoding='utf-8') as f:
  87. config = json.load(f)
  88. required_fields = ["front", "backend", "title", "ui_design_style"]
  89. for field in required_fields:
  90. if field not in config:
  91. return False
  92. # 检查UI设计风格值
  93. valid_styles = ["corporate", "cyberpunk", "minimal"]
  94. if config.get("ui_design_style") not in valid_styles:
  95. return False
  96. return True
  97. except (json.JSONDecodeError, Exception):
  98. return False
  99. def test_script_syntax(self):
  100. """测试脚本语法正确性"""
  101. python_scripts = [
  102. "init_project.py",
  103. "check_project.py",
  104. "generate_all_sourcecode.py"
  105. ]
  106. for script in python_scripts:
  107. script_path = self.project_dir / script
  108. if script_path.exists():
  109. try:
  110. result = subprocess.run(
  111. [sys.executable, "-m", "py_compile", str(script_path)],
  112. capture_output=True,
  113. text=True,
  114. cwd=self.project_dir
  115. )
  116. if result.returncode != 0:
  117. return False
  118. except Exception:
  119. return False
  120. return True
  121. def test_ui_design_specs(self):
  122. """测试UI设计规范文件"""
  123. ui_specs = [
  124. "specs_docs/ui_design_specs/01-UI设计规范_默认_Corporate.md",
  125. "specs_docs/ui_design_specs/02-UI设计规范_暗黑科技风格_Cyberpunk.md",
  126. "specs_docs/ui_design_specs/03-UI设计规范_极简主义风格_Minimal.md"
  127. ]
  128. for spec in ui_specs:
  129. spec_path = self.project_dir / spec
  130. if not spec_path.exists():
  131. return False
  132. # 检查文件是否为空
  133. if spec_path.stat().st_size == 0:
  134. return False
  135. return True
  136. def test_system_prompts(self):
  137. """测试AI系统提示词文件"""
  138. prompts = [
  139. "system_prompts/01-软著框架系统提示词.md",
  140. "system_prompts/02-页面规划系统提示词.md",
  141. "system_prompts/03-界面设计系统提示词.md",
  142. "system_prompts/04-网页代码生成系统提示词.md",
  143. "system_prompts/05-数据库代码生成系统提示词.md",
  144. "system_prompts/06-后端代码生成系统提示词.md",
  145. "system_prompts/07-用户手册系统提示词.md",
  146. "system_prompts/08-软件著作权登记信息表系统提示词.md"
  147. ]
  148. for prompt in prompts:
  149. prompt_path = self.project_dir / prompt
  150. if not prompt_path.exists():
  151. return False
  152. # 检查文件是否包含基本内容
  153. try:
  154. with open(prompt_path, 'r', encoding='utf-8') as f:
  155. content = f.read()
  156. if len(content.strip()) < 100: # 至少100个字符
  157. return False
  158. except Exception:
  159. return False
  160. return True
  161. def test_check_script_functionality(self):
  162. """测试检查脚本功能"""
  163. check_script = self.project_dir / "scripts" / "validators" / "check_project.py"
  164. if not check_script.exists():
  165. return False
  166. try:
  167. # 运行快速检查
  168. result = subprocess.run(
  169. [sys.executable, str(check_script), "--quick"],
  170. capture_output=True,
  171. text=True,
  172. cwd=self.project_dir,
  173. timeout=30 # 30秒超时
  174. )
  175. # 检查脚本是否能正常运行(退出码0、1、2都是正常的)
  176. return result.returncode in [0, 1, 2]
  177. except Exception:
  178. return False
  179. def test_init_script_import(self):
  180. """测试初始化脚本导入"""
  181. init_script = self.project_dir / "scripts" / "init" / "init_project.py"
  182. if not init_script.exists():
  183. return False
  184. try:
  185. # 测试脚本是否可以正常导入
  186. result = subprocess.run(
  187. [sys.executable, "-c",
  188. f"import sys; sys.path.insert(0, '{self.project_dir}'); "
  189. f"exec(open('{init_script}').read().split('if __name__')[0])"],
  190. capture_output=True,
  191. text=True,
  192. timeout=10
  193. )
  194. return result.returncode == 0
  195. except Exception:
  196. return False
  197. def test_documentation_completeness(self):
  198. """测试文档完整性"""
  199. docs = [
  200. "README.md",
  201. "01-快速开始.md",
  202. "02-安装指南.md",
  203. "03-使用说明.md",
  204. "04-故障排除.md",
  205. "05-FAQ.md",
  206. "00-文档导航.md",
  207. "ROADMAP.md",
  208. "FEATURE_LIST.md",
  209. "BUG_FIXES_LOG.md",
  210. "06-项目检查指南.md"
  211. ]
  212. for doc in docs:
  213. doc_path = self.project_dir / doc
  214. if not doc_path.exists():
  215. return False
  216. # 检查文档是否有基本内容
  217. try:
  218. with open(doc_path, 'r', encoding='utf-8') as f:
  219. content = f.read()
  220. if len(content.strip()) < 200: # 至少200个字符
  221. return False
  222. except Exception:
  223. return False
  224. return True
  225. def test_template_creation(self):
  226. """测试模板项目创建(模拟)"""
  227. with tempfile.TemporaryDirectory() as temp_dir:
  228. try:
  229. # 创建测试配置文件
  230. test_config = {
  231. "front": "React",
  232. "backend": "Node.js",
  233. "title": "测试软件系统",
  234. "short_title": "测试系统",
  235. "ui_design_style": "corporate"
  236. }
  237. test_config_path = Path(temp_dir) / "ai-copyright-config.json"
  238. with open(test_config_path, 'w', encoding='utf-8') as f:
  239. json.dump(test_config, f, ensure_ascii=False, indent=2)
  240. # 验证文件创建成功
  241. return test_config_path.exists()
  242. except Exception:
  243. return False
  244. def run_all_tests(self):
  245. """运行所有测试"""
  246. self.print_colored(Colors.PURPLE, "🚀 开始AI软著申请材料生成系统自动化测试")
  247. self.print_colored(Colors.BLUE, f"📁 测试目录: {self.project_dir}")
  248. tests = [
  249. ("项目结构完整性", self.test_project_structure),
  250. ("配置文件有效性", self.test_config_file_validity),
  251. ("脚本语法正确性", self.test_script_syntax),
  252. ("UI设计规范文件", self.test_ui_design_specs),
  253. ("AI系统提示词文件", self.test_system_prompts),
  254. ("检查脚本功能", self.test_check_script_functionality),
  255. ("初始化脚本导入", self.test_init_script_import),
  256. ("文档完整性", self.test_documentation_completeness),
  257. ("模板创建功能", self.test_template_creation)
  258. ]
  259. passed = 0
  260. total = len(tests)
  261. for test_name, test_func in tests:
  262. if self.run_test(test_name, test_func):
  263. passed += 1
  264. # 生成测试报告
  265. return self.generate_test_report(passed, total)
  266. def generate_test_report(self, passed: int, total: int):
  267. """生成测试报告"""
  268. self.print_header("测试报告汇总")
  269. success_rate = (passed / total) * 100 if total > 0 else 0
  270. self.print_colored(Colors.CYAN, f"📊 测试统计:")
  271. self.print_colored(Colors.GREEN, f" ✅ 通过: {passed}")
  272. self.print_colored(Colors.RED, f" ❌ 失败: {total - passed}")
  273. self.print_colored(Colors.BLUE, f" 📋 总计: {total}")
  274. self.print_colored(Colors.PURPLE, f" 💯 成功率: {success_rate:.1f}%")
  275. # 计算总耗时
  276. total_time = sum(result.get("duration", 0) for result in self.test_results)
  277. self.print_colored(Colors.CYAN, f" ⏱️ 总耗时: {total_time:.2f}s")
  278. print("\n" + "="*60)
  279. if passed == total:
  280. self.print_colored(Colors.GREEN, "🎉 所有测试通过!系统功能正常。")
  281. return 0
  282. elif success_rate >= 80:
  283. self.print_colored(Colors.YELLOW, f"⚠️ {total - passed} 个测试失败,但系统基本可用。")
  284. return 1
  285. else:
  286. self.print_colored(Colors.RED, f"❌ {total - passed} 个测试失败,系统存在严重问题。")
  287. # 显示失败的测试
  288. failed_tests = [r for r in self.test_results if r["status"] != "PASS"]
  289. if failed_tests:
  290. self.print_colored(Colors.RED, "\n🔧 失败的测试:")
  291. for i, test in enumerate(failed_tests[:3], 1):
  292. self.print_colored(Colors.RED, f" {i}. {test['name']} - {test['status']}")
  293. if len(failed_tests) > 3:
  294. self.print_colored(Colors.RED, f" ... 还有 {len(failed_tests) - 3} 个失败测试")
  295. return 2
  296. def main():
  297. """主函数"""
  298. import argparse
  299. parser = argparse.ArgumentParser(
  300. description='AI软著申请材料生成系统 - 自动化测试工具',
  301. formatter_class=argparse.RawDescriptionHelpFormatter,
  302. epilog="""
  303. 使用示例:
  304. python3 run_tests.py # 测试当前目录
  305. python3 run_tests.py /path/to/project # 测试指定目录
  306. """
  307. )
  308. parser.add_argument(
  309. 'project_dir',
  310. nargs='?',
  311. default='.',
  312. help='项目目录路径(默认为当前目录)'
  313. )
  314. args = parser.parse_args()
  315. # 解析项目目录
  316. project_dir = Path(args.project_dir).resolve()
  317. if not project_dir.exists():
  318. print(f"{Colors.RED}❌ 项目目录不存在: {project_dir}{Colors.NC}")
  319. sys.exit(1)
  320. if not project_dir.is_dir():
  321. print(f"{Colors.RED}❌ 指定路径不是目录: {project_dir}{Colors.NC}")
  322. sys.exit(1)
  323. # 创建测试运行器并执行
  324. runner = TestRunner(project_dir)
  325. return runner.run_all_tests()
  326. if __name__ == "__main__":
  327. sys.exit(main())