8. 一键出报告,结果填入HTML模板

发布时间:2026/8/9 3:45:36

8. 一键出报告,结果填入HTML模板
配套动画视频在《8. 一键出报告结果填入HTML模板》源代码在《评论区置顶》。截图有了还差一份能打开看的测试报告。这一节把结果填进 HTML 模板先声明工具入参再把输出路径和截图路径规范到工程内有 test_results.json 就读并合并用例截图没有则从文本里解析总计/通过/失败。接着用 Jinja2 把结果填进 templates/report_template.html写出能本地打开的网页并返回通过率任一步异常则返回错误信息。模板要用到 Jinja2提前装好即可pip install Jinja2先定义工具入参test_output 是结果文本output_path 是报告保存路径screenshots 是截图路径列表。调用时要把截图路径传进来否则报告里看不到图。工具名是 generate_test_reportAgent 按这个名字调用class GenerateReportInput(BaseModel): test_output: str Field(description测试输出结果) screenshots: list Field(default_factorylist, description截图路径列表) output_path: str Field(description报告保存路径) class GenerateReportTool(BaseTool): name: str generate_test_report description: str 根据测试结果生成HTML测试报告 args_schema: Type[BaseModel] GenerateReportInput_run 里先做路径规范化。传入的路径可能是 /testcases/...也可能是相对路径。用 _resolve 统一成工程根目录下的绝对路径截图列表里每一项同样处理。screenshots 为 None 时按空列表处理。整个 _run 包在 try/except 里任一步异常都返回错误信息def _run(self, test_output: str, output_path: str, screenshots: list None) - str: base_dir os.path.dirname(os.path.abspath(__file__)) def _resolve(path): if path.startswith(/): return os.path.normpath(os.path.join(base_dir, path.lstrip(/))) return path if os.path.isabs(path) else os.path.normpath( os.path.join(base_dir, path)) output_path _resolve(output_path) if screenshots is None: screenshots [] screenshots [_resolve(s) for s in screenshots]取数时优先看 testcases/test_results.json。有就 json.load并把每个用例 screenshots 里的 path 合并进截图列表。没有 JSON就调用 _parse_output 从 test_output 文本里解析总计、通过和失败results_file os.path.join(base_dir, testcases, test_results.json) if os.path.exists(results_file): with open(results_file, r, encodingutf-8) as f: test_results json.load(f) for tc in test_results.get(test_cases, []): for s in tc.get(screenshots, []): p s.get(path) if isinstance(s, dict) else s if p and p not in screenshots: screenshots.append(p) else: test_results self._parse_output(test_output)渲染阶段根据 passed/total 算通过率 rate把外部传入的 screenshots 与各用例内截图去重合并成 all_shots用 FileSystemLoader 加载 templates/report_template.html把 results、rate、type_labels、all_shots、report_dir 和 to_relative_path 传给模板。to_relative_path 把截图绝对路径转成相对报告文件的路径并把反斜杠换成 /本地打开 HTML 时图片才能显示report_dir os.path.dirname(os.path.abspath(output_path)) rate (results[passed] / results[total] * 100) if results[total] 0 else 0 type_labels {before: 测试前, after: 测试后, failed: 失败时, error: 错误时, step: 步骤截图} all_shots [] seen set() for s in screenshots: if s not in seen: all_shots.append(s) seen.add(s) template_dir os.path.join(os.path.dirname(os.path.abspath(__file__)), templates) env Environment(loaderFileSystemLoader(template_dir)) template env.get_template(report_template.html) def to_relative_path(abs_path: str, base_dir: str) - str: try: rel os.path.relpath(abs_path, base_dir) return rel.replace(\\, /) except Exception: return abs_path.replace(\\, /) html template.render( resultsresults, raterate, type_labelstype_labels, all_shotsall_shots, report_dirreport_dir, to_relative_pathto_relative_path) return html最后调用 _build_html 得到完整 HTML 字符串确保输出目录存在再写入 output_path。返回值带上总计、通过、失败和通过率中间抛异常时返回「生成报告失败…」html self._build_html(test_results, screenshots, output_path) output_file Path(output_path) output_file.parent.mkdir(parentsTrue, exist_okTrue) with open(output_file, w, encodingutf-8) as f: f.write(html) total test_results.get(total, 0) passed test_results.get(passed, 0) failed test_results.get(failed, 0) rate (passed / total * 100) if total 0 else 0 return f报告生成成功{output_path}\n总计:{total} 通过:{passed} f失败:{failed} 通过率:{rate:.1f}%要把启停截图和出报告串起来可以用 open_app_screenshot_close_report先调用 open_app_screenshot_close 拿到 shot_path再拼一份单用例结构的 test_results 写入 test_results.json最后调用 GenerateReportTool._runscreenshots 参数带上 [shot_path]报告页面里才会有这张图shot_path open_app_screenshot_close(screenshot_path) passed 1 if shot_path else 0 failed 0 if shot_path else 1 case_shots [] if shot_path: case_shots.append({type: step, label: app_screenshot, path: shot_path}) test_results { total: 1, passed: passed, failed: failed, test_cases: [{ case_id: TC_OPEN_SHOT_CLOSE, case_name: 启动App截图关闭, status: passed if shot_path else failed, screenshots: case_shots, }], } with open(results_file, w, encodingutf-8) as f: json.dump(test_results, f, ensure_asciiFalse, indent2) shot_list [shot_path] if shot_path else [] report_msg GenerateReportTool()._run(, report_path, shot_list)这样从启停截图到 HTML 报告就接上了本地打开报告文件就能看到通过率和对应截图。配套动画视频在《8. 一键出报告结果填入HTML模板》源代码在《评论区置顶》。

相关新闻

AI安全实践:从RSI框架到可落地的模型风险评估与管控

AI安全实践:从RSI框架到可落地的模型风险评估与管控

2026/8/9 3:45:36

这次我们来看一个很有意思的现象:AI 公司一边在公开场合自嘲“AI 失控”,一边却在内部或对特定受众大力鼓吹 RSI(Responsible Scaling Policies,负责任扩展策略)。这看似矛盾的行为背后,其实反映了当前 AI …

Agent Runtime架构设计:从Prompt到可校验执行链路的工程实践

Agent Runtime架构设计:从Prompt到可校验执行链路的工程实践

2026/8/9 3:45:36

1. 从 Prompt 到执行:为什么我们需要一个“运行时”?如果你最近在折腾 AI 应用开发,尤其是想搞点能自主完成复杂任务的智能体(Agent),那你肯定对这两个词不陌生:Prompt和Agent Runtime。前者是给…

AI Agent架构设计:从直觉到工程的Plan-and-Execute模式解析

AI Agent架构设计:从直觉到工程的Plan-and-Execute模式解析

2026/8/9 3:45:36

1. 从直觉到架构:为什么“边想边干”在AI Agent里行不通聊到AI Agent,很多人脑子里蹦出来的第一个画面,可能就是ChatGPT那种一问一答,或者让它写个邮件、改个代码,它“思考”一下(也就是生成一段文本&#…

Rhino.Inside.Revit终极指南:3个简单步骤实现参数化设计与BIM协同的革命

Rhino.Inside.Revit终极指南:3个简单步骤实现参数化设计与BIM协同的革命

2026/8/9 11:25:56

Rhino.Inside.Revit终极指南:3个简单步骤实现参数化设计与BIM协同的革命 【免费下载链接】rhino.inside-revit This is the open-source repository for Rhino.Inside.Revit 项目地址: https://gitcode.com/gh_mirrors/rh/rhino.inside-revit Rhino.Inside.R…

隧道代理与自建代理池的技术对比与应用场景

隧道代理与自建代理池的技术对比与应用场景

2026/8/9 11:25:56

1. 项目概述:隧道代理与自建代理池的技术博弈 第一次接触隧道代理是在三年前的一个电商爬虫项目,当时自建的代理池突然大面积失效,导致整个数据采集系统瘫痪。在紧急寻找替代方案时,我发现了这个号称"无需维护IP资源"的…

KMS_VL_ALL_AIO:3分钟实现Windows和Office永久激活的智能解决方案

KMS_VL_ALL_AIO:3分钟实现Windows和Office永久激活的智能解决方案

2026/8/9 11:25:56

KMS_VL_ALL_AIO:3分钟实现Windows和Office永久激活的智能解决方案 【免费下载链接】KMS_VL_ALL_AIO Smart Activation Script 项目地址: https://gitcode.com/gh_mirrors/km/KMS_VL_ALL_AIO 还在为系统激活问题而烦恼吗?KMS_VL_ALL_AIO智能激活脚…

实际使用中,广西OPC创客中心能提供哪些AI工具资源?

实际使用中,广西OPC创客中心能提供哪些AI工具资源?

2026/8/9 11:25:56

想在广西搞创业,却愁没合适的AI工具资源?广西OPC创客中心就能解决这一难题。我朋友之前在玉林做牛仔生意,参加线下展会成本高,线上曝光又不足,客源很不稳定。后来在广西OPC创客中心的帮助下,情况有了很大改…

Java应用离线License授权系统设计:从非对称加密到硬件指纹绑定实战

Java应用离线License授权系统设计:从非对称加密到硬件指纹绑定实战

2026/8/9 11:25:56

1. 项目概述最近在做一个面向企业客户的Java桌面应用,客户那边提了个硬性要求:软件必须支持离线环境下的授权验证。说白了,就是软件卖出去后,客户可能在内网甚至完全断网的环境里用,我们得确保软件是正版授权的&#x…

GPT-5.6与新版Codex:社区AI模型代理环境搭建与排错指南

GPT-5.6与新版Codex:社区AI模型代理环境搭建与排错指南

2026/8/9 11:15:55

最近在AI开发圈里,一个话题的热度正在悄然攀升:GPT-5.6和新版Codex。如果你在搜索引擎里输入这些关键词,会发现大量关于安装、使用、报错和接入的讨论。但信息非常零散,很多开发者,尤其是刚接触AI应用开发的&#xff0…

比较好的亚太EMBA,问了6位校友师资差别真的挺大

比较好的亚太EMBA,问了6位校友师资差别真的挺大

2026/8/9 0:05:25

比较好的亚太EMBA核心差异先看什么?对于希望兼顾工作与系统管理能力提升的亚太区高管而言,筛选匹配度高的EMBA项目时,师资配置是决定学习体验与实际收获的核心要素之一。我们结合3-4个公开信息透明、办学历史较长的亚太区主流EMBA项目特点&am…

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

2026/8/9 0:05:25

备考海外游学的亚洲EMBA面试,核心要围绕项目国际化设计逻辑、个人跨文化管理经验匹配度两个维度准备,避免把游学模块等同于普通旅游参访的认知偏差。不少备考者花3个月对比6份资料,却容易忽略面试官对“国际视野落地能力”的考察——比如香港…

比较好的国内EMBA,问了二十位校友聊透人脉价值

比较好的国内EMBA,问了二十位校友聊透人脉价值

2026/8/9 0:05:25

比较好的国内EMBA核心差异体现在哪些方面?比较好的国内EMBA的核心长期价值,很大程度上依托于校友网络的连接质量与资源生态的活跃度,这也是不少高管在择校时优先考量的因素。我们结合3-4个市场关注度较高的项目公开信息,从课程、师…

比较好的亚太EMBA,问了6位校友师资差别真的挺大

比较好的亚太EMBA,问了6位校友师资差别真的挺大

2026/8/9 0:05:25

比较好的亚太EMBA核心差异先看什么?对于希望兼顾工作与系统管理能力提升的亚太区高管而言,筛选匹配度高的EMBA项目时,师资配置是决定学习体验与实际收获的核心要素之一。我们结合3-4个公开信息透明、办学历史较长的亚太区主流EMBA项目特点&am…

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

备考3个月对比6份资料 海外游学的亚洲EMBA面试注意点

2026/8/9 0:05:25

备考海外游学的亚洲EMBA面试,核心要围绕项目国际化设计逻辑、个人跨文化管理经验匹配度两个维度准备,避免把游学模块等同于普通旅游参访的认知偏差。不少备考者花3个月对比6份资料,却容易忽略面试官对“国际视野落地能力”的考察——比如香港…

比较好的国内EMBA,问了二十位校友聊透人脉价值

比较好的国内EMBA,问了二十位校友聊透人脉价值

2026/8/9 0:05:25

比较好的国内EMBA核心差异体现在哪些方面?比较好的国内EMBA的核心长期价值,很大程度上依托于校友网络的连接质量与资源生态的活跃度,这也是不少高管在择校时优先考量的因素。我们结合3-4个市场关注度较高的项目公开信息,从课程、师…

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

2026/8/8 5:07:31

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…

导师推荐!2026最新AI论文工具测评与实用推荐

导师推荐!2026最新AI论文工具测评与实用推荐

2026/8/7 8:02:42

2026年真正好用的AI论文工具,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

告别游戏崩溃:XCOM 2模组管理器的智能革命

告别游戏崩溃:XCOM 2模组管理器的智能革命

2026/8/8 2:30:15

告别游戏崩溃:XCOM 2模组管理器的智能革命 【免费下载链接】xcom2-launcher The Alternative Mod Launcher (AML) is a replacement for the default game launchers from XCOM 2 and XCOM Chimera Squad. 项目地址: https://gitcode.com/gh_mirrors/xc/xcom2-lau…