简介:这份PDF是一份完整的软件测试方向毕业实习报告,面向计算机科学与技术、软件工程等专业的在校生与即将进入测试岗位的求职者,可用于撰写实习报告、整理实习材料,或了解企业测试工作的真实流程。报告以葛洲坝集团电力有限责任公司的四周实习为主线,依次记录企业背景与产品认知、软件测试基础知识学习(测试用例、测试流程、测试类型与常用工具)、测试环境搭建与功能测试、用例编写与执行、bug提交与回归验证,以及测试进度计划、日报周报等文档规范,另含实习目的、单位介绍、过程记录与总结反思等章节,可直接参照其结构组织自己的报告。资源为1个PDF文件,压缩包约745KB,体积轻巧便于下载查阅。目前已有63人学习下载,适合想了解测试岗位日常职责、文档写作要求与实习报告框架的读者参考借鉴。
1. 软件测试毕业实习报告.pdf:一份能拿得出手的交付物长什么样
实习三个月,需求评审参加了七次,接口用例写了两百多条,缺陷提了四十个,回归跑了三轮。到答辩前一天,这些动作绝大部分还躺在禅道的列表页、Jira 的看板、和同事的聊天记录里。最后交上去的实习报告,往往是几张贴图加一段「在本次实习中我学到了很多」——面试官翻两页就放下了。
这个标题要解决的,是把散落的测试动作收敛成一份结构固定、数据可核对、能全文检索的 PDF:内容侧要覆盖软件测试流程、用例设计、缺陷跟踪和度量指标,工程侧要能从 Markdown 或 HTML 稳定产出带目录、页码、中文字体的 PDF 文档。它适合正在准备实习答辩和秋招简历的测试新人,也适合带实习生的测试组长直接拿去做模板。下面按内容骨架、PDF 生成、数据来源、交付自检四段推进,每段都给出可复现的命令和代码。
2. 软件测试毕业实习报告的内容骨架:测试流程、用例与缺陷怎么落笔
2.1 先定章节:一份实习报告该有哪些固定模块
实习报告和测试总结报告不是一回事。测试总结面向项目,讲版本质量;实习报告面向个人成长,讲你在这套软件测试流程里承担了哪一段、用什么方法做的、结果能不能被别人复算。我一般会把它拆成六个固定模块,顺序别乱:
第一段写项目背景与被测系统边界,一两段就够,说清被测的是 Web 后台、移动端 App 还是嵌入式固件,测试环境是什么版本。第二段写参与的测试流程环节,这是后面所有内容的骨架。第三段写用例设计方法与产出,用等价类、边界值、场景法各举一个真实例子,比列二十条用例编号更有效。第四段写缺陷跟踪,按严重等级和状态分布给数据。第五段写度量与结论,用执行率、缺陷密度、缺陷收敛趋势三个指标收口。第六段写复盘,只写具体的能力短板,不写客套话。
模块定好之后,每个模块标题直接对应一个 Markdown 二级标题,后面生成 PDF 时目录会自动抽出来。这也是为什么我不建议先开 Word 再想结构——结构没定就排版,改一次要重排一次。
2.2 软件测试流程怎么写成可核对的证据链
软件测试流程常见的划分是:需求评审 → 测试计划 → 用例设计 → 用例评审 → 执行 → 缺陷提交与跟踪 → 回归 → 测试报告。实习报告里最容易写虚的就是这一段,因为「参加了需求评审」这句话谁都能写。
把它写成证据链的办法是给每个环节挂一个可验证的产出物和一次参与记录。需求评审环节,产出物是评审意见条目,写清楚你提了几条、被采纳几条,比如「针对订单超时关闭逻辑提出 3 条歧义点,其中 2 条进入需求澄清记录」。测试计划环节,产出物是范围与排期表,写清你负责的模块占整体用例的比例。用例设计环节产出用例集,执行环节产出执行记录,缺陷环节产出缺陷单。回归环节写清回归范围和触发条件,例如「修复单影响支付回调,触发支付链路全量回归」。
注意:每个环节的产出物必须是别人能查到的,写「禅道项目 XX 下第 3 轮迭代」比写「参与了缺陷管理」有用得多。
这样写还有个副作用,面试时被追问「你负责的部分边界在哪」时,你可以直接用模块占比和用例数量回答,不需要现场回忆。
2.3 用例与缺陷:表格字段和度量口径
缺陷单的字段不是随便定的,它决定了你后面能不能算出有意义的指标。下面这张表是我在报告里固定用的字段集,前六列直接从测试管理工具导出,后三列是补充口径。
| 字段 | 类型 | 说明 | 用途 |
|---|---|---|---|
| 缺陷编号 | 字符串 | 工具内唯一标识 | 追溯与去重 |
| 所属模块 | 枚举 | 与用例模块保持一致 | 缺陷密度分母对齐 |
| 严重等级 | 枚举 | 致命/严重/一般/提示 | 分布统计 |
| 优先级 | 枚举 | P0-P3 | 修复排期核对 |
| 发现阶段 | 枚举 | 冒烟/系统/回归/验收 | 缺陷逃逸分析 |
| 状态 | 枚举 | 新建/修复中/已修复/关闭/挂起 | 收敛趋势 |
| 首次发现轮次 | 整数 | 第几轮执行发现 | 收敛曲线横轴 |
| 关联用例 | 字符串 | 触发缺陷的用例编号 | 反向验证用例有效性 |
| 是否重复 | 布尔 | 重复单标记 | 剔除后重算总数 |
口径上有两个坑。一是重复缺陷必须剔除后再算缺陷密度,否则同一模块的总数会虚高。二是「已修复」不等于「已关闭」,收敛趋势应该按「未关闭缺陷数」画,而不是按「新建缺陷数」画,因为前者才反映版本是否真的收敛。
度量公式也要在报告里显式写出,让读者能复算:用例执行率等于已执行用例数除以计划用例总数;缺陷密度等于去重后缺陷数除以对应模块的用例数;遗留缺陷率等于关闭前未关闭缺陷数除以总缺陷数。三个数都保留两位小数。
2.4 用脚本把执行数据算成报告里的结论
手工数这三组数字很容易出错,尤其是跨轮次统计的时候。我一般把工具导出的用例执行记录存成 CSV,用一段脚本直接算,结果直接贴进报告,避免手抖。
# metrics.py 从测试管理工具导出的 CSV 计算报告核心指标 import csv from collections import defaultdict def load(path): with open(path, newline='', encoding='utf-8-sig') as f: return list(csv.DictReader(f)) rows = load('cases_export.csv') # 期望字段: case_id, module, status(通过/失败/阻塞/未执行), round, bug_id, is_duplicate plan_total = len(rows) executed = [r for r in rows if r['status'] != '未执行'] exec_rate = len(executed) / plan_total # 用例执行率 module_cases = defaultdict(int) # 每模块用例数,做密度分母 bugs = set() for r in rows: module_cases[r['module']] += 1 if r['bug_id'] and r['is_duplicate'] == '0': bugs.add(r['bug_id']) # 去重后缺陷集合 density = {m: round(sum(1 for r in rows if r['module'] == m and r['bug_id'] and r['is_duplicate'] == '0') / c, 2) for m, c in module_cases.items()} print(f'计划用例 {plan_total},执行率 {exec_rate:.2%}') for m, d in sorted(density.items(), key=lambda x: -x[1]): print(f'{m}: 缺陷密度 {d}')脚本里status字段的取值必须和工具导出口径对齐,如果有「未执行」和「跳过」两种状态,要在过滤条件里都排除,否则执行率会偏低。is_duplicate用 0/1 而不是布尔值,是因为 CSV 导出常见的是字符串,直接比较会更稳。密度分母用的是「该模块用例数」而不是「该模块执行用例数」,这两个口径的差别要在报告里注明,否则换个人算出来的数对不上。
3. 从 Markdown 到软件测试毕业实习报告.pdf:Pandoc 与 WeasyPrint 两条路线
3.1 工具选型:为什么我不推荐直接在 Word 里排版
Word 排版的问题不在好不好看,在于不可版本化。每次改一处用例数据就要重新对齐图注、页码和目录,改到第三版基本就放弃维护了。用纯文本写内容、用工具生成 PDF,改数据只需要改一行文字,重新跑一次命令。
常见路线有四条,差异主要在中文支持和排版控制力上:
| 路线 | 输入 | 中文支持 | 排版控制 | 适合场景 |
|---|---|---|---|---|
| Pandoc + LaTeX | Markdown | 需配 CJK 字体 | 强,模板复杂 | 长文档、公式多 |
| WeasyPrint + CSS | HTML | 好,直接用系统字体 | 强,CSS 分页 | 报告类、图表多 |
| reportlab | Python 代码 | 需注册字体 | 中,需手写布局 | 程序化生成固定版式 |
| Word 导出 | docx | 好 | 弱,易错版 | 必须交 docx 时 |
实习报告这种图表多、公式少、要反复改数据的文档,我倾向 WeasyPrint;如果报告里要塞测试覆盖率公式和大量数学符号,Pandoc 更省事。
3.2 Pandoc + LaTeX 路线的最小可用命令
# 1. 先装好 TeX 发行版和 pandoc,确认中文字体存在 # fc-list :lang=zh | head (Linux/macOS 下查可用中文字体) pandoc report.md \ -o 软件测试毕业实习报告.pdf \ --pdf-engine=xelatex \ --toc --toc-depth=3 \ -V mainfont="Noto Serif CJK SC" \ -V monofont="Noto Sans Mono CJK SC" \ -V geometry:margin=2.5cm \ -V fontsize=11pt \ --number-sections--pdf-engine=xelatex是必须的,pdflatex 处理中文要走复杂的 CJK 宏包,xelatex 直接调系统字体。--toc生成目录,--toc-depth=3表示抽到三级标题,报告里###一般是小节,抽三级刚好。mainfont和monofont要分开放,正文用衬线、代码用等宽,如果只配一个,代码块里的中文会变成方块。--number-sections给章节自动编号,但要注意它会把一级标题编号成 1、2、3,如果你的报告里已经手写了「1.1」这种编号,会变成双重编号,那就去掉这个参数。
geometry:margin=2.5cm是页边距,报告要打印的话别低于 2cm,否则装订边会被裁掉。
3.3 WeasyPrint + CSS 路线:中文字体与分页控制
WeasyPrint 走的是 HTML + CSS 分页媒体,好处是 CSS 里能直接写分页规则,控制力比 LaTeX 模板直观。
# build_pdf.py 把 Markdown 转 HTML 再生成 PDF import markdown from weasyprint import HTML, CSS with open('report.md', encoding='utf-8') as f: text = f.read() # tables 扩展让 2.3 节的表格正常渲染,toc 扩展自动生成目录锚点 html_body = markdown.markdown( text, extensions=['tables', 'fenced_code', 'toc', 'codehilite'], extension_configs={'toc': {'toc_depth': '2-3'}} ) html_doc = f'''<!DOCTYPE html><html><head><meta charset="utf-8"> <title>软件测试毕业实习报告</title></head><body>{html_body}</body></html>''' # 显式指定字体,避免容器里缺字体导致中文变方块 base_css = CSS(string=''' @page { size: A4; margin: 2.5cm 2cm; @bottom-center { content: counter(page) " / " counter(pages); } } body { font-family: "Noto Serif CJK SC", "Source Han Serif SC", serif; font-size: 11pt; line-height: 1.7; } pre, code { font-family: "Noto Sans Mono CJK SC", monospace; font-size: 9pt; } table { border-collapse: collapse; width: 100%; font-size: 10pt; } th, td { border: 1px solid #999; padding: 4px 8px; } h1 { page-break-before: always; } /* 每章另起一页 */ h2, h3 { page-break-after: avoid; } /* 标题不与正文分离 */ img { max-width: 100%; } ''') HTML(string=html_doc, base_url='.').write_pdf('软件测试毕业实习报告.pdf', stylesheets=[base_css]) print('done')extension_configs里的toc_depth写2-3,只在##和###上生成目录项,一级标题如果就是文档标题,不进目录更干净。@bottom-center里用counter(page)和counter(pages)生成「当前页 / 总页数」,这是 CSS 分页媒体的标准写法,比后处理 PDF 加页码可靠。h1 { page-break-before: always; }会把每个一级标题强制推到新页,报告体量不大时可以去掉,省纸。
base_url='.'是给相对路径图片用的,2.4 节生成的趋势图放在同目录,Markdown 里写就能引到。如果字体报 warning,用fc-list :lang=zh确认字体名,CSS 里的名称必须和系统注册名完全一致,差一个空格都会回退到默认字体。
3.4 目录、页眉页脚与图表编号的落地配置
WeasyPrint 支持用target-counter做「目录页码」,但需要手写锚点链接。更省事的做法是用markdown的toc扩展生成带id的标题,再在 CSS 里给目录链接补页码,配置复杂度不低。实习报告这种十几页的文档,我的选择是目录不标页码,只列层级,页码靠 PDF 阅读器的书签导航——生成的 PDF 已经带书签,检索和跳转都够用。
图表编号建议手工写进题注,不要指望工具自动编号。比如图注统一写成「图 4-1 缺陷收敛趋势(第 1-3 轮)」,章号对齐章节序号,正文里用「见图 4-1」引用。理由很简单:工具自动编号在插入新图后会全部重排,而手工编号配合版本管理,改动范围可控。
页眉如果需要放报告名和日期,在@page里加@top-right { content: "软件测试毕业实习报告"; },但注意@page默认对所有页生效,封面页要去掉的话得单独定义一个命名页规则并在封面元素上引用。
4. 报告里的数据从哪来:pytest、JUnit XML 与缺陷趋势图
4.1 自动化执行结果导出成可解析的结构
实习期间如果做过接口自动化,pytest 是大概率用过的工具,它可以直接把结果输出成 JUnit XML,这个格式几乎所有测试平台和 CI 都认,也是报告数据最稳的来源。
# 生成 JUnit XML 和 HTML 两份结果,XML 用来算数,HTML 用来截图放附录 pytest tests/ \ --junit-xml=results/junit.xml \ --html=results/report.html --self-contained-html \ -m "not slow" \ -q--junit-xml输出的是标准 XML,字段有tests、failures、errors、skipped和时间属性。-m "not slow"排除慢用例,实习报告里通常统计的是主链路用例,慢用例单列。--self-contained-html把 CSS 和图片内联进单个 HTML 文件,避免发给别人时丢样式,但它不适合直接转 PDF,因为分页控制差,正确做法是 HTML 只作附录截图。
4.2 解析 JUnit XML 统计通过率与失败分布
XML 里的失败信息带堆栈,直接统计会把同一个根因重复计数。我一般按「失败用例所属模块」聚合,再看模块维度上哪块最弱。
# parse_junit.py 按模块统计通过率与失败分布 import xml.etree.ElementTree as ET from collections import defaultdict tree = ET.parse('results/junit.xml') root = tree.getroot() suite = root if root.tag == 'testsuite' else root.find('testsuite') stat = defaultdict(lambda: {'total': 0, 'fail': 0, 'error': 0, 'skip': 0}) for case in suite.iter('testcase'): # classname 形如 tests.test_order.TestOrder,取模块段做分组键 module = case.get('classname', '').split('.')[1] or 'unknown' stat[module]['total'] += 1 if case.find('failure') is not None: stat[module]['fail'] += 1 elif case.find('error') is not None: stat[module]['error'] += 1 elif case.find('skipped') is not None: stat[module]['skip'] += 1 for m, s in sorted(stat.items(), key=lambda x: -(x[1]['fail'] + x[1]['error'])): passed = s['total'] - s['fail'] - s['error'] - s['skip'] rate = passed / s['total'] if s['total'] else 0 print(f'{m:20s} 用例 {s["total"]:3d} 通过率 {rate:.1%} ' f'失败 {s["fail"]} 错误 {s["error"]} 跳过 {s["skip"]}')分组键取classname的第二段,是因为 pytest 默认把tests/test_order.py::TestOrder::test_x映射成tests.test_order.TestOrder,第一段固定是tests,第二段才是模块名。如果你的目录结构不是这样,直接打印几个classname看实际格式再改切分下标。
跳过用例不参与通过率分母还是参与,两种口径都能用,但必须在报告里写清楚。我一般让跳过用例参与分母,因为跳过通常意味着环境缺失,这类风险应该被计入。
4.3 缺陷趋势图:用 matplotlib 生成并嵌入 PDF
收敛趋势图是报告里最有说服力的一张图,横轴是执行轮次,纵轴是未关闭缺陷数。数据从缺陷导出表里按「首次发现轮次」和「关闭轮次」两张字段算。
# bug_trend.py 画缺陷收敛曲线,输出矢量图供 PDF 引用 import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # rounds: 轮次;opened: 各轮新增;closed: 各轮关闭 rounds = [1, 2, 3, 4] opened = [18, 12, 6, 2] closed = [0, 9, 15, 20] plt.rcParams['font.sans-serif'] = ['Noto Sans CJK SC'] # 中文字体 plt.rcParams['axes.unicode_minus'] = False remain, cur = [], 0 for o, c in zip(opened, closed): cur += o - c remain.append(max(cur, 0)) fig, ax = plt.subplots(figsize=(6, 3.2), dpi=150) ax.plot(rounds, remain, marker='o', color='#c0392b', label='未关闭缺陷') ax.bar(rounds, opened, alpha=0.25, color='#7f8c8d', label='新增缺陷') ax.set_xlabel('执行轮次'); ax.set_ylabel('缺陷数') ax.set_xticks(rounds); ax.grid(axis='y', linestyle='--', alpha=0.4) ax.legend() fig.tight_layout() fig.savefig('bug_trend.svg') # 矢量图,PDF 里放大不糊 print('saved bug_trend.svg')fig.savefig的格式选 SVG 而不是 PNG,因为 PDF 是矢量容器,嵌 SVG 后放大打印不糊;如果用的是 WeasyPrint,SVG 也能直接引用。plt.rcParams['font.sans-serif']必须显式指定中文字体,不然图例里的中文会变成一堆方框,这个问题和 3.3 节的字体是同一类坑。max(cur, 0)是防御性写法,当关闭数大于累计新增时,累计剩余会出现负数,图表上会画出很怪的下沉,钳到 0 更符合实际含义。
figsize用 6×3.2 是按 PDF 正文宽度约 16cm 反推的,图片插入后基本满宽不缩放,字看着最舒服。dpi=150对 SVG 无影响,但对同时导出的 PNG 版本有效,报告中需要嵌入 Word 或聊天工具时用得上。
4.4 手工测试数据的采集口径与清洗
实习期间手工测试占比通常不低于自动化,这部分数据靠人在工具里录,清洗规则要提前定。我自己的三条规则是:第一,执行记录必须带轮次,没有轮次的记录不进趋势图;第二,同一用例同一轮只保留最后一条状态,前面的算覆盖写;第三,缺陷的「发现阶段」字段必填,否则无法做逃逸分析——也就是有多少缺陷是回归阶段才暴露的,这个数直接反映用例覆盖率。
清洗后的数据再和 4.2 的自动化统计做交叉核对:如果自动化显示某模块通过率 100%,但手工又在该模块提了缺陷,说明自动化用例覆盖不到这类场景,这条结论写进报告比单列一堆数据有价值得多。常见做法是把交叉结果放进「用例有效性」一小节,用两句话说明结论,不需要额外图表。
5. 交付前的 PDF 自检:文本提取、字体嵌入与一页纸摘要
PDF 生成完不要直接交。在线投递和系统解析都会读 PDF 文本层,如果字体没嵌好或者文字被转成曲线,检索和复制会直接失效,面试官搜「缺陷密度」搜不到你的报告。自检第一步就是提取文本确认可读:
# verify_pdf.py 交付前自检:文本层、页数、关键词覆盖 import pdfplumber REQUIRED = ['测试流程', '用例设计', '缺陷密度', '回归', '测试报告'] with pdfplumber.open('软件测试毕业实习报告.pdf') as pdf: print(f'总页数: {len(pdf.pages)}') text = '\n'.join((p.extract_text() or '') for p in pdf.pages) for kw in REQUIRED: print(f'{"OK " if kw in text else "MISS"} {kw}') # 检查是否出现方块字:中文字符占比过低说明字体回退失败 zh = sum(1 for ch in text if '\u4e00' <= ch <= '\u9fff') print(f'中文字符 {zh},占比 {zh / max(len(text), 1):.1%}')extract_text()返回空字符串通常意味着该页是纯图片或文字被转曲,这两种情况都要重做,转曲一般来自把 PDF 又过了一遍虚拟打印。关键词列表按报告结构挑五个,缺哪个就说明对应章节被漏掉或者标题写得太口语化。中文占比低于 20% 要警惕,正常中文报告这个值在 35% 以上。
第二步查字体嵌入,命令行一条就够:pdffonts 软件测试毕业实习报告.pdf,输出里每一行的 emb 列必须是 yes。有 no 的行说明该字体依赖阅读器本机字体,换台机器就可能显示异常,尤其是用到思源、Noto 这类不一定预装的字体时。
第三步做一页纸摘要。实习报告二十页很正常,但面试官只看前三分钟。摘要放封面之后,用一张表列关键数:计划用例数、执行率、去重缺陷数、缺陷密度、遗留缺陷率、自动化用例占比,每个数字后面标出对应的报告章节号。这张表也是简历里「软件测试实习」那一条的数据来源,写简历时直接抄,不用再回头翻正文。
最后一个小技巧:投递用的文件名把版本和日期带上,比如软件测试毕业实习报告_v3_20250610.pdf。系统解析和人工归档都靠文件名区分,同名文件覆盖一次,你就得重新导一遍 PDF。
本文还有配套的精品资源,点击获取