ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

测试年度总结报告PDF自动化生成:从数据采集到校验的流水线实践

测试年度总结报告PDF自动化生成:从数据采集到校验的流水线实践 简介这是一份PDF版测试年度总结报告适合软件测试初学者、从业者及关注测试团队管理的人员阅读。内容以作者进入测试行业后的成长经历为主线梳理了集成测试、系统测试、CMM等基础概念的学习困惑重点强调利用搜索引擎和组合关键词、词组搜索、定位信息等技巧解决工作难题对提升日常排错效率很有帮助。报告还收录了2019年软件测试年终总结围绕企业内部管理、资金/物资/人力/信息四类资源及人力资源管理短板展开分析提出建立规范化、制度化、有凝聚力团队的方向。资源共1个PDF文件大小1.11MB已有60人学习下载。对于想了解测试职业发展路径和年终总结写法的人可从中获取可借鉴的经验与思考框架。1. 测试年度总结报告.pdf交付物而非文档年底的测试总结通常不是写给测试自己看的而是写给项目组、质量委员会和明年预算看的。正因为这样测试年度总结报告会越来越多地以 PDF 形态交付格式固定、不可被随意改动、评审和归档都方便。但多数团队的实际情况是这份 PDF 靠人工从缺陷库和 CI 后台翻数据再粘贴进模板耗时一天且数字经常对不上。这篇文章就把“测试年度总结报告.pdf”当作一条数据流水线来拆解数据从哪里采、统计口径怎么定、用什么工具生成、生成后如何反向校验目标是让这份报告从手工作业变成可复现的产物。适合 QA 负责人、测试开发以及所有需要把测试数据整理成正式交付物的工程师。2. 从测试平台与 CI 拉取数据测试年度总结报告.pdf 的数据源头2.1 先想清楚PDF 里要出现哪些数据写年度总结报告之前得先确定这份 PDF 要回答哪些问题。一般团队会放三块用例执行情况、自动化运行结果、缺陷趋势。每一块的数据都分散在不同系统里直接手动导出再合并后面清洗会非常痛苦。数据项典型来源获取方式用例执行记录测试管理平台JIRA Xray、禅道、TestRailREST API 按时间范围导出CI 构建与自动化运行Jenkins、GitLab CIJob API 读取构建记录缺陷数据JIRA、Redmine、禅道问题跟踪系统 API 按项目与时间查询代码覆盖率与变更量SonarQube、Git以 commit 时间关联到版本先把这个表列出来后面每一步都知道数据从哪个接口来。这里有个原则报告生成逻辑必须可以在下一年原样再跑一遍所以任何一步都不要依赖人工从网页复制粘贴。2.2 用脚本拉取最小可运行示例以 JIRA 缺陷拉取为例最常见的是走标准 REST API。下面这段是用 requests 分页取完一年缺陷的骨架。import requests from requests.auth import HTTPBasicAuth JIRA_URL https://jira.example.com/rest/api/2/search JIRA_USER qa-bot JIRA_TOKEN xxxx # 查出过去一年所有缺陷只取摘要、状态、创建时间 jql project APP and issuetype Bug and created 2025-01-01 and created 2025-12-31 resp requests.get( JIRA_URL, params{jql: jql, fields: summary,status,created, maxResults: 100}, authHTTPBasicAuth(JIRA_USER, JIRA_TOKEN), timeout30, ) resp.raise_for_status() data resp.json() issues data[issues] # JIRA 默认分页 50 条需要按 startAt 循环直到取完 total while len(issues) data[total]: resp requests.get( JIRA_URL, params{ jql: jql, fields: summary,status,created, maxResults: 100, startAt: len(issues), }, authHTTPBasicAuth(JIRA_USER, JIRA_TOKEN), timeout30, ) resp.raise_for_status() issues.extend(resp.json()[issues])这段代码先把时间边界写死在 JQL 里保证每年切换报告周期时只需改两个日期。fields参数控制返回列尽量只取后面要用的字段接口响应会小很多。status在后续清洗时会用到所以这里连同 name 一起取出来。raise_for_status()的作用是快速暴露接口异常否则报告季拉数据时可能静默失败最后生成的 PDF 数字是缺的。Jenkins 的读取方向不太一样一般不是按时间过滤而是先取构建列表再筛时间。常见做法是用 tree 参数指定需要的字段避免一次性把整个构建历史拉下来import requests jenkins_url https://jenkins.example.com/job/backend-test/api/json params {tree: builds[number,timestamp,result,duration]{0,200}} resp requests.get(jenkins_url, paramsparams, timeout30) resp.raise_for_status() builds resp.json()[builds]tree 语法里的{0,200}是范围限定意思是只需要最近 200 次构建。timestamp是毫秒级 Unix 时间戳后面统计“xx 月跑了几次自动化”时要先用 Python 的datetime.fromtimestamp(ts / 1000)转成本地时间。2.3 先落盘再加工把原始记录存成 CSV接口拉下来的数据不要直接拿去算指标先落一份原始 CSV。这样当 PDF 里的数字和源系统页面对不上时可以回到这份 CSV 核对是拉取问题还是清洗问题。import csv from datetime import date out_file fraw_bugs_{date.today().isoformat()}.csv with open(out_file, w, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([key, status, created]) for issue in issues: fields issue[fields] writer.writerow([issue[key], fields[status][name], fields[created]])落盘格式建议 CSV 或 SQLite。CSV 的好处是可以用 Excel 快速抽查SQLite 适合后续做多表 join。注意encodingutf-8和newline这两个参数前者避免 Windows 下写入乱码后者防止 csv 模块在行尾多出空行。文件名带日期是习惯报告季每天拉一次数据时不会覆盖昨天的原始记录。2.4 容易漏掉的两个时间边界问题第一是时区。Jenkins 默认按 UTC 存储时间戳国内服务器一般显示 UTC8直接用字符串日期过滤会把当天 0 点到 8 点的构建算到前一天。处理方式是在拉取后统一用astimezone转换例如构建时间戳先转成Asia/Shanghai再截取日期。第二是接口时间精度。有的平台 created 字段带毫秒有的不带字符串比较年份时格式要统一。最简单的做法是拉取时就把时间列转成YYYY-MM-DD后续所有统计都基于这个标准化日期。提示落盘时保留原始字段不要只存清洗后的结果。原始数据是排错的锚点丢了就只能重新拉接口。3. 统计口径决定 PDF 里的数字三处最容易被质疑的计算3.1 用例执行数按“条”还是按“次”这是个很容易在评审会上被问住的问题。自动化用例一天跑了五轮状态依次是失败、失败、通过、通过、通过如果按“次”统计执行数失败数被放大了好几倍通过率也会偏低。年度总结报告里我一般建议拆成两个指标执行次数作为“工作量”展示通过率按“条”计算即每个用例每天只取最后一次执行结果。import pandas as pd df pd.read_csv(executions.csv) # 每个用例每天取最后一次执行 daily_latest ( df.sort_values(started_at) .groupby([case_id, run_date]) .tail(1) ) # 按用例条数算通过率 pass_rate ( daily_latest[daily_latest[result] PASS][case_id].nunique() / daily_latest[case_id].nunique() )sort_values是为了让tail(1)拿到的是当天最后一次执行而不是文件里的最后一行。nunique()是去重计数这里配合按条统计的口径保证同一个用例不会因为重跑多次而拉高整体比例。3.2 自动化通过率的分子分母评审会上第二个常问的是分母里到底包不包括阻塞和跳过的用例。如果把被环境阻塞、被产品决策跳过的用例放进分母通过率会被明显拉低而且这个数字很难解释清楚。建议把分母定义为“明确执行且有结果的用例”分子是执行结果为 PASS 的用例。def compute_pass_rate(df): executed df[df[result].isin([PASS, FAIL])] passed executed[executed[result] PASS] return passed[case_id].nunique() / executed[case_id].nunique()这里用isin([PASS, FAIL])把阻塞、跳过、未执行全部排除在分母之外。口径一旦确定就要写进报告模板的附注里否则明年换一个人统计很可能把分母改成全部用例数字立刻就变了。3.3 缺陷的有效率与关闭率状态流转只取最终态缺陷的统计比用例更绕。一条缺陷可能经历 Open → Reopen → Closed → Reopen 的状态流转如果直接按导出时点统计每个时间点看到的状态都不一样。年度报告要的是最终态即截止到 12 月 31 日这条缺陷最后处于什么状态。bug_history pd.read_csv(bug_history.csv) last_status ( bug_history.sort_values(changed_at) .groupby(bug_key) .tail(1) )groupby(bug_key).tail(1)取每个缺陷按时间排序后的最后一条记录保证一条缺陷只进一次统计。缺陷有效率常见定义是“非无效缺陷 / 已核实缺陷”但“无效”在不同团队含义不同有的是产品设计如此有的是重复提交有的是环境问题。在生成 PDF 之前需要先和项目组确认这些分类的归属否则数字会存在争议。3.4 对账PDF 里的总数必须和源系统一致统计口径定了之后先别急着生成 PDF先做一次对账。把最终要写进报告的几个关键数字打印出来和源系统页面上的计数对比。脏数据来源表现处理方式同一用例重复执行通过率虚高或虚低按 case_id 日期去重时区偏移日期边界差一天统一转时区后再截取日期缺陷状态多条历史缺陷数重复计数按 bug_key 分组取最终态对账应该在原始 CSV 上进行不要在生成 PDF 之后再从 PDF 里取数核对。PDF 是排版产物不是数据源从里面反推数字只能用于检验不能用于修正。4. 用 Python 生成测试年度总结报告.pdf模板、图表、字体三个关键设置4.1 选型WeasyPrint 更适合年度报告生成 PDF 常见有三条路ReportLab 纯代码排版、HTML 转 PDF、先出 HTML 再让用户自己打印。年度测试总结报告的特点是表格多、趋势图多、还要能自动分页用 HTML CSS 来排版是最省力的。方案适合场景主要问题ReportLab精确控制坐标、动态绘制表格和分页代码冗长中文字体要手动注册WeasyPrintHTMLCSS 排版打印友好依赖系统中文字体生成速度略慢浏览器直接打印 HTML快速预览不同浏览器打印样式不一致页眉页脚难统一我一般用 WeasyPrint。它支持标准 CSS 分页、表格跨页自动重复表头、内置页码计数器对年度报告这种结构化文档很合适。4.2 最小可运行模板HTML CSS Jinja2用 Jinja2 渲染数据到 HTML 模板再交给 WeasyPrint 输出 PDF是最常见的一套组合。from jinja2 import Template from weasyprint import HTML html_template !DOCTYPE html html langzh-CN head meta charsetutf-8 style page { size: A4; margin: 2cm; bottom-center { content: counter(page); } } body { font-family: Noto Sans CJK SC, sans-serif; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #333; padding: 4px 8px; } /style /head body h1测试年度总结报告.pdf/h1 table trth指标/thth数值/th/tr trtd执行用例数/tdtd{{ executed }}/td/tr trtd自动化通过率/tdtd{{ pass_rate }}/td/tr /table /body /html html_str Template(html_template).render(executed1200, pass_rate92.5%) HTML(stringhtml_str).write_pdf(年度测试总结.pdf)重点说几个参数。page里的size: A4和margin: 2cm是页面基础设置bottom-center中的content: counter(page)是 WeasyPrint 内置的页面计数器不用额外写页码逻辑。font-family要写系统中的中文字体名称Linux 下一般是Noto Sans CJK SCmacOS 可以是PingFang SC。注意这里用HTML(string...)直接传字符串也可以传文件路径但在 CI 里字符串方式更可控避免路径问题。4.3 图表matplotlib 用 Agg 后端输出 PNG 再 base64 内嵌年度总结报告里通常要放通过率趋势图、缺陷收敛图。在无显示环境的服务器上matplotlib 必须指定 Agg 后端否则会报 TclError 或找不到显示设备的错误。import matplotlib matplotlib.use(Agg) import matplotlib.pyplot as plt import base64 import io fig, ax plt.subplots(figsize(8, 4), dpi140) ax.plot([1, 2, 3, 4], [88, 90, 91, 92.5], markero) ax.set_title(测试通过率趋势) ax.set_xlabel(季度) ax.set_ylabel(通过率 %) ax.set_ylim(80, 100) buf io.BytesIO() fig.savefig(buf, formatpng, bbox_inchestight) buf.seek(0) img_base64 base64.b64encode(buf.read()).decode(utf-8) # 模板中引用img srcdata:image/png;base64,{{img_base64}}把图表以 base64 内嵌进 HTML生成的单个 PDF 文件可以独立分发不需要附带图片目录。这里的dpi140是经过权衡的低于 100 放大后文字发虚高于 200 会让 PDF 体积增长很快140 左右在 A4 页面肉眼看起来足够清晰。bbox_inchestight去掉坐标轴外多余白边否则图表在页面上会显得偏小。4.4 字体与分页的坑中文字体缺失是生成报告时最常踩的坑表现是 PDF 里中文全部显示为方框。生成前先在服务器上确认字体存在fc-list | grep -i noto.*cjk没有输出就安装字体包Debian/Ubuntu 下是fonts-noto-cjk。安装后 WeasyPrint 不需要重启服务重新生成即可。另一个常见问题是表格跨页时被中间截断表头不会自动重复。WeasyPrint 支持thead机制把表头行放在thead里跨页时会自动在下一页重复显示。5. 生成后的自检反向解析测试年度总结报告.pdf 并核对数字5.1 用 pdfplumber 提取文字与表格PDF 生成完不意味着结束。我习惯在生成脚本后接一个校验脚本用 pdfplumber 把写进 PDF 的数字提取出来和源数据比对防止模板里变量写错、数字被格式化截断这类问题。import pdfplumber with pdfplumber.open(年度测试总结.pdf) as pdf: print(pages:, len(pdf.pages)) first pdf.pages[0] text first.extract_text() tables first.extract_tables()extract_text()用来检查标题、章节名是否正常渲染extract_tables()抽出表格内容接下来可以断言里面的关键数字是否和预期一致。5.2 断言模板里的关键数字假设模板中写入了自动化通过率 92.5%用下面的方式从 PDF 中提取并验证import math expected_pass_rate 92.5 found None with pdfplumber.open(年度测试总结.pdf) as pdf: for page in pdf.pages: for table in page.extract_tables(): for row in table: if row and 自动化通过率 in row: found float(row[1].strip(%)) assert found is not None assert math.isclose(found, expected_pass_rate, abs_tol0.1)这里用math.isclose而不是是因为 PDF 中显示的是92.5%但解析出来可能是92.500或者92.5浮点转换后直接比较容易出问题。abs_tol0.1的容差足够捕捉模板变量写错、数据源用错这类错误同时不会因为格式化差异误报。5.3 检查书签、页数、文本溢出除了数字还要验证 PDF 结构是否完整。多页报告建议检查大纲书签评审时跳转章节很方便页数是否符合预期避免模板渲染异常导致只剩一页。文本溢出较难直接判断常见做法是用page.chars检查字符的x1坐标是否超出页面右边界用来定位表格最后一列被挤出页面的情况。把校验脚本接到生成命令之后用串联失败时以非零码退出报告季谁改模板都会先被这台校验机拦住。本文还有配套的精品资源点击获取
返回列表