简介:《软件测试毕业实习报告》以单份PDF文档形式呈现,面向计算机科学与技术、软件工程等专业临近毕业、需要完成实习报告或准备踏入测试岗位的学生。全文围绕葛洲坝集团电力有限责任公司的四周测试实习展开,依次记录实习目的、实习单位介绍、实习内容与逐周过程,涵盖电力管理系统软件的功能模块认知、测试用例编写与执行、测试环境搭建、QC缺陷管理、bug提交与回归测试、日报周报撰写等环节,并附有可编辑的学院实习报告封面与成绩评定表,可直接参考格式与写法。资源包共1个pdf文件,约745KB,篇幅紧凑、便于打印与二次编辑,目前已有63人学习下载。读者可据此了解企业级软件测试的真实工作流程与文档规范,获取理论联系实际的写作思路,也可作为实习报告模板与小论文素材,适合初入测试领域的学习者查漏补缺。
1. 软件测试毕业实习报告.pdf:这份交付物真正的难点在哪
实习最后一周,导师或 HR 要的往往是一个固定的文件名:软件测试毕业实习报告.pdf。卡住人的通常不是测试知识,而是交付——Word 另存成 PDF 之后目录没书签、页码从封面开始算、代码块被拦腰截断、截图放大全是噪点、附录的缺陷表跨页错位。
这份文件是两条并行的活。内容侧要把实习期间做的事按软件测试流程固化成证据链:测试计划、用例设计、执行记录、缺陷单、回归结论、量化指标;工程侧要把源文件稳定渲染成 PDF,再反过来解析校验页数、关键字、书签层级和图片清晰度。
正在写报告的实习生、要统一交付格式的测试组长、负责批量导出的测试开发,都能在后面找到可直接抄的骨架、命令和参数。先从内容骨架开始,再谈渲染和校验。
2. 软件测试毕业实习报告的内容骨架:测试流程、用例与缺陷数据怎么落笔
报告被打回重写的常见理由不是"写得少",而是"看不出做过什么"。评审人翻三页就想确认一件事:这个人是否真的走过一遍完整的软件测试流程,手里有没有可核查的数据。所以章节顺序不要按"周记"排,按流程排。
2.1 用测试流程把报告章节串成一条线
常见做法是把报告主体对齐到八个阶段:需求评审、测试计划、用例设计、环境与数据准备、用例执行、缺陷提交与跟踪、回归验证、测试报告与复盘。每个阶段在报告里回答三个问题——输入是什么、我做了什么、产出物在哪一页。
| 报告章节 | 对应流程阶段 | 产出物 | 可量化字段 |
|---|---|---|---|
| 第 2 章 测试范围与策略 | 需求评审、测试计划 | 测试计划书、范围清单 | 需求条数、覆盖模块数 |
| 第 3 章 用例设计 | 用例设计 | 用例集、脑图、评审记录 | 用例总数、需求覆盖率 |
| 第 4 章 执行与缺陷 | 环境准备、执行、跟踪 | 执行记录、缺陷单 | 执行率、通过率、缺陷密度 |
| 第 5 章 回归与结论 | 回归验证、复盘 | 回归报告、遗留缺陷表 | 回归通过率、修复率 |
提示:实习报告里最容易露怯的是"测试环境"一节。写清操作系统版本、浏览器或客户端版本、被测服务版本号、数据库版本,别只写"Windows 环境"。
2.2 用例设计表与执行记录怎么写才经得起核查
用例表最少要有这些列:用例 ID、所属模块、前置条件、操作步骤、预期结果、实际结果、优先级、执行结果、执行人、执行时间。步骤要能被另一个人照着复现,预期结果要能判定真假,避免"界面正常""功能可用"这类无法判定的描述。
如果实习期间写了自动化用例,把结果文件直接转成统计数据,比手数用例靠谱。pytest 生成的 junit XML 就是一份现成的原始数据:
# 执行用例并输出 junit 格式结果,供报告统计使用 pytest tests/ --junitxml=reports/junit.xml -qimport xml.etree.ElementTree as ET tree = ET.parse("reports/junit.xml") root = tree.getroot() total = passed = failed = skipped = 0 for case in root.iter("testcase"): total += 1 # failure 与 error 都算失败,skipped 单独统计 if case.find("failure") is not None or case.find("error") is not None: failed += 1 elif case.find("skipped") is not None: skipped += 1 else: passed += 1 print(f"用例总数 {total} 通过 {passed} 失败 {failed} 跳过 {skipped}") print(f"通过率 {passed / total:.2%}")这段代码遍历所有testcase节点,逐个判断子节点类型:有failure或error记为失败,有skipped记为跳过,其余记为通过。total不直接用root的tests属性,是为了避免部分插件不写该属性时统计为空。把输出数字抄进报告的"执行结果"小节,同时在附录贴一段原始 XML 片段,数字就有出处了。
2.3 缺陷数据与量化指标:缺陷密度、执行率、遗留缺陷
答辩最常被追问的一句话是"这个通过率怎么算的"。指标必须在报告里写出公式和口径,比如跳过用例算不算进分母、重复提交的缺陷算一条还是两条。
-- 按模块统计本轮用例执行情况,通过率升序排列,方便定位薄弱模块 SELECT module, COUNT(*) AS total_cases, SUM(CASE WHEN result = 'PASS' THEN 1 ELSE 0 END) AS passed, ROUND(SUM(CASE WHEN result = 'PASS' THEN 1 ELSE 0 END) * 1.0 / COUNT(*), 4) AS pass_rate FROM test_case_execution WHERE round_id = 'R2024-11' GROUP BY module ORDER BY pass_rate ASC;-- 缺陷密度 = 该模块缺陷数 / 模块千行代码数 SELECT b.module, COUNT(*) AS defects, m.kloc, ROUND(COUNT(*) * 1.0 / NULLIF(m.kloc, 0), 2) AS defect_density FROM bug b JOIN module_size m ON m.module = b.module WHERE b.found_round = 'R2024-11' GROUP BY b.module, m.kloc ORDER BY defect_density DESC;第一条 SQL 按模块聚合执行结果,CASE WHEN把布尔式结果折算成 1 和 0 再做求和,避免用COUNT(result='PASS')这种在多数数据库里不成立的写法。第二条里的NULLIF(m.kloc, 0)用来防止除零,模块规模为空或为零时该行返回 NULL 而不是报错。指标表建议在报告里固定为四行:用例执行率、用例通过率、缺陷密度、遗留缺陷数,并注明统计截止时间。
2.4 容易被追问的三处细节
第一处是环境与版本,报告里出现的每一个版本号都要能对应到截图或日志。第二处是缺陷复现步骤,只写"偶现"而不给触发条件,评审人基本会认定这份缺陷单是凑数的。第三处是数据来源口径,比如"缺陷总数 87 条"要说明是否包含已关闭的重开单、是否包含非本轮发现的历史遗留。把这三处写实,报告的可信度会明显高于堆页数。
3. 把 Markdown 渲染成软件测试毕业实习报告.pdf:Pandoc、XeLaTeX 与 WeasyPrint 流水线
内容写完之后,真正的排版工作量才开始。用 Markdown 写正文、用工具链渲染 PDF,最大的好处是格式可以版本管理:改一处字体、加一个页眉,重跑一条命令即可,不用在 Word 里手动调 60 页的样式。
3.1 为什么不建议 Word 直接另存为 PDF
Word 另存为 PDF 的问题集中在三点:目录是静态文字而不是 PDF 书签,评审人无法在阅读器侧栏跳转;代码块和表格遇到分页会被硬切,跨页后背景色和边框经常丢失;页码、页眉在封面和正文之间难以分段设置。这些问题不是不能解决,而是每次改动都要重新手工核对一遍。
常见做法是源文件用 Markdown,渲染走两条路:装了 TeX 环境就用 Pandoc + XeLaTeX,排版质量高、公式支持好;不想装几个 G 的 TeX,就用 Pandoc + WeasyPrint,纯 CSS 控制,改起来快。
3.2 Pandoc + XeLaTeX 的中文字体与页边距参数
# 生成带三级目录、章节编号、中文字体的 PDF pandoc report.md \ -o 软件测试毕业实习报告.pdf \ --pdf-engine=xelatex \ --toc --toc-depth=3 \ --number-sections \ -V documentclass=ctexart \ -V geometry:"top=2.5cm,bottom=2.5cm,left=2.8cm,right=2.8cm" \ -V CJKmainfont="Noto Serif CJK SC" \ -V mainfont="Noto Sans" \ -V fontsize=11pt \ -V linestretch=1.4 \ --highlight-style=tango \ --resource-path=.| 参数 | 作用 | 常见取值 |
|---|---|---|
--pdf-engine | 指定渲染引擎 | xelatex支持中文,weasyprint走 CSS |
--toc-depth | 目录收录到几级标题 | 报告建议 3,太深会占两页 |
--number-sections | 章节自动编号 | 与学校模板要求一致时再开 |
-V CJKmainfont | 中文字体 | 必须填本机已安装的字体全名 |
-V geometry | 页边距 | 与模板要求误差控制在 2mm 内 |
--resource-path | 图片搜索路径 | 写相对路径,便于迁移 |
CJKmainfont填错是最高频的失败原因,报错通常是Font ... not found,用fc-list :lang=zh查一下本机装了哪些中文字体再填。documentclass=ctexart会接管中文断行和标点挤压,不要同时手动加载xeCJK。
3.3 WeasyPrint + CSS 做页码、页眉与 PDF 书签
不装 TeX 时,用 CSS 的分页规则控制版式,书签由bookmark-level生成:
@page { size: A4; margin: 22mm 20mm 20mm 20mm; @top-center { content: "软件测试毕业实习报告"; font-size: 9pt; color: #666; } @bottom-right { content: counter(page) " / " counter(pages); font-size: 9pt; } } /* 封面不显示页眉页码 */ @page :first { @top-center { content: none; } @bottom-right { content: none; } } h1 { break-before: page; bookmark-level: 1; bookmark-label: content(text); } h2 { bookmark-level: 2; bookmark-label: content(text); } h3 { bookmark-level: 3; bookmark-label: content(text); } /* 代码块、表格、图片禁止内部断开 */ pre, table, figure { break-inside: avoid; }pandoc report.md -o 软件测试毕业实习报告.pdf \ --pdf-engine=weasyprint \ --css=style.css --toc --standalonecounter(page)与counter(pages)由 WeasyPrint 在排版阶段解析,页码会自动跟随实际页数。break-before: page让每个一级标题另起一页,适合章节结构规整的报告;如果篇幅紧张,把它去掉页面能省下好几页。bookmark-label: content(text)表示书签标题取标题文字本身,漏写这一行会导致侧栏书签显示为空。
3.4 代码块跨页、字体缺字与截图 DPI 的处理
代码块跨页靠break-inside: avoid只能减少概率,超长代码块仍然会被切开,稳妥做法是把长代码按功能拆成多个短块,并在块前用一句说明交代上下文。中文字体缺字通常表现为 PDF 里某些字变方框,原因是渲染时的字体回退链里没有覆盖到该字符,在 CSS 里补一条font-family: "Noto Sans", "Noto Sans CJK SC", sans-serif;即可。
截图是最影响观感的环节。测试报告里的界面截图建议按 150% 到 200% 缩放后再截,导出时保证不低于 300 DPI,否则在 A4 页面上放大看就是一片虚影。截图里的敏感信息在生成前处理掉,别指望在 PDF 上用白色矩形盖住——那层矩形是可以被删掉的。
4. 反过来校验 PDF:pdfplumber 与 pypdf 解析软件测试毕业实习报告
渲染完成不等于交付完成。页数够不够、关键字在不在、附录表格有没有丢、书签层级对不对,这些靠肉眼翻页检查很容易漏,写个脚本几秒钟就能跑完一遍。
4.1 pdfplumber 抽取文本做关键字与空页校验
import pdfplumber REQUIRED = ["测试计划", "用例执行率", "缺陷密度", "回归测试结论", "遗留缺陷"] with pdfplumber.open("软件测试毕业实习报告.pdf") as pdf: print("总页数:", len(pdf.pages)) text = "\n".join((p.extract_text() or "") for p in pdf.pages) # 关键字命中检查 for kw in REQUIRED: print(f"{kw}: {'命中' if kw in text else '缺失'}") # 空页与近空页检查,常见于分页符过多 for i, p in enumerate(pdf.pages, 1): body = (p.extract_text() or "").strip() if len(body) < 20 and not p.images: print(f"第 {i} 页疑似空白,字符数 {len(body)}")extract_text()返回的是按版面还原的文本,代码块里的内容也会被抽出来,所以关键字检查放在全文层面即可。空白页判定给了两个条件:文本字符数少于 20 且页面无图片,避免把整页截图误判成空白。p.images会返回页面图像对象列表,扫描件类 PDF 的文本提取结果通常为空,这时要靠pypdf读页数、靠图像处理单独判断。
4.2 pypdf 检查书签层级、页数与元数据
from pypdf import PdfReader reader = PdfReader("软件测试毕业实习报告.pdf") print("页数:", len(reader.pages)) print("元数据:", reader.metadata) def walk(items, depth=0): for it in items: if isinstance(it, list): # 嵌套列表代表更深一层书签 walk(it, depth + 1) else: print(" " * depth + str(it.title)) walk(reader.outline)reader.outline是一个混合结构:书签项和子书签列表交替出现,所以递归时先判断类型是list还是书签对象。把输出和目录页对照一遍,能立刻发现"目录写了三级、书签只到二级"这类问题。元数据里的/Title、/Author会显示在阅读器标题栏,用 Pandoc 的--metadata title=...或 pypdf 的add_metadata补上。
| 校验项 | 检查手段 | 判定标准 |
|---|---|---|
| 页数 | len(reader.pages) | 与目录最后页码一致 |
| 关键字 | pdfplumber 全文检索 | 关键小节标题 100% 命中 |
| 书签层级 | 递归reader.outline | 至少覆盖到二级标题 |
| 空白页 | 文本长度 +p.images | 无异常空页 |
| 图片清晰度 | 提取图像尺寸 / 显示尺寸 | 有效 DPI 不低于 150 |
4.3 把历史 PDF 资料转成可检索文本与表格
实习期间收集的参考资料、往届报告常常是 PDF,想引用其中内容就得先转出来。文本类 PDF 直接用 pdfplumber 抽取,表格类资料用extract_tables()会保留行列结构:
import pdfplumber with pdfplumber.open("往届缺陷记录.pdf") as pdf: for page_no, page in enumerate(pdf.pages, 1): for table in page.extract_tables(): for row in table: # None 代表合并单元格的填充位,统一替换成空串 print(["" if c is None else c.replace("\n", " ") for c in row])需要保留排版直接转 Word 时,可以用 pdf2docx 的命令行:pdf2docx convert 缺陷记录.pdf 缺陷记录.docx。它按页面结构还原段落和表格,转换结果仍需人工核对,尤其是跨页表格和带旋转文字的页眉。扫描件走的是另一条路,先做 OCR 再谈文本检索。
4.4 扫描件与虚拟打印件的纠偏、去噪与清晰度处理
用扫描仪或虚拟打印机生成的 PDF,常见问题是整页轻微倾斜,导致 OCR 识别率骤降。用 OpenCV 估算文字块的最小外接矩形角度,再整体旋转即可纠偏:
import cv2 import numpy as np img = cv2.imread("scan.png", cv2.IMREAD_GRAYSCALE) # OTSU 自动阈值 + 反色,让文字变成前景白点 binary = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] coords = np.column_stack(np.where(binary > 0)) angle = cv2.minAreaRect(coords.astype(np.float32))[-1] # minAreaRect 返回的角度超过 -45 度时需要换算成小角度 if angle < -45: angle = 90 + angle h, w = img.shape[:2] M = cv2.getRotationMatrix2D((w // 2, h // 2), angle, 1.0) rotated = cv2.warpAffine(img, M, (w, h), flags=cv2.INTER_CUBIC, borderMode=cv2.BORDER_REPLICATE) cv2.imwrite("scan_fixed.png", rotated) print(f"纠正角度 {angle:.2f}")THRESH_BINARY_INV把深色文字变成亮色前景,np.where取出所有前景像素坐标交给minAreaRect求角度。旋转用INTER_CUBIC插值,边缘用BORDER_REPLICATE复制边界像素,避免出现黑边影响后续识别。偏色或灰底严重的页面,先做一次自适应直方图均衡再二值化,字符边缘会干净很多;这一步做完再合成回 PDF,比在某些编辑器里逐页调对比度省事。
5. 软件测试毕业实习报告.pdf 提交前的合并、压缩与自动校验
前面几步产出的是分件:封面、正文、附录缺陷记录。提交要求通常是一个文件,还可能限制体积。这一段把合并、水印、压缩和校验串成一条命令链。
5.1 封面、正文与附录的合并与页码一致性
from pypdf import PdfWriter, PdfReader writer = PdfWriter() for path in ["封面.pdf", "正文.pdf", "附录缺陷记录.pdf"]: for page in PdfReader(path).pages: writer.add_page(page) writer.add_metadata({ "/Title": "软件测试毕业实习报告", "/Author": "张三", "/Subject": "软件测试实习总结", }) with open("软件测试毕业实习报告.pdf", "wb") as f: writer.write(f)合并只是把页对象顺序拼接,正文里已经渲染好的页码不会自动重排。要保证"封面不编码、正文从 1 开始",做法是渲染时用@page :first去掉封面页码,并把正文单独渲染一次再合并,而不是合并后手工改数字。合并完成后重新跑一遍第 4.2 节的书签检查,确认书签没有在拼接过程中丢失。
5.2 加水印与体积压缩的取舍
需要标注"内部资料"时,用一层水印 PDF 叠加到每一页:
from pypdf import PdfReader, PdfWriter stamp = PdfReader("水印.pdf").pages[0] writer = PdfWriter() for page in PdfReader("软件测试毕业实习报告.pdf").pages: page.merge_page(stamp) # 水印页需与正文页同尺寸 writer.add_page(page) with open("软件测试毕业实习报告_已标注.pdf", "wb") as f: writer.write(f)水印 PDF 的页面尺寸必须与正文一致,否则叠加会错位,A4 正文就做一个 595×842 磅的水印页。压缩用 Ghostscript,-dPDFSETTINGS=/ebook会把嵌入图片降到 150 DPI 左右,一份 40MB 的截图型报告通常能压到 5MB 以内。压缩后务必再跑一次书签与关键字校验,部分压缩路径会丢弃大纲信息。
5.3 一条命令跑完的交付校验脚本
把第 4 章的两段检查合成一个返回非零退出码的脚本,接在渲染命令之后:
#!/usr/bin/env bash set -euo pipefail PDF="软件测试毕业实习报告.pdf" pandoc report.md -o "$PDF" --pdf-engine=weasyprint \ --css=style.css --toc --standalone python check_pdf.py "$PDF" # 内部含关键字、空页、书签三项检查import sys import pdfplumber from pypdf import PdfReader path = sys.argv[1] REQUIRED = ["测试计划", "用例执行率", "缺陷密度", "回归测试结论"] errors = [] with pdfplumber.open(path) as pdf: text = "\n".join((p.extract_text() or "") for p in pdf.pages) if len(pdf.pages) < 15: errors.append(f"页数偏少:{len(pdf.pages)}") for kw in REQUIRED: if kw not in text: errors.append(f"缺少关键字:{kw}") reader = PdfReader(path) if len(reader.outline) == 0: errors.append("PDF 无书签") if errors: print("\n".join(errors)) sys.exit(1) print("校验通过")set -euo pipefail保证渲染失败时脚本立刻停止,不会拿着上一版旧 PDF 继续校验。校验脚本用退出码表达结果,接进 CI 或本地提交前的钩子都合适。返回值非 0 时先看它打印的是第几页缺关键字、还是书签整体为空——前者回源文件补内容,后者回第 3 章的 CSS 或 Pandoc 参数里查bookmark-level与--toc-depth是否被漏掉,改完重跑那条渲染命令即可。
本文还有配套的精品资源,点击获取