简介:一份以Python为核心的自动化测试系统毕业论文资源,主要面向专科、本科毕业生及自动化测试初学者。论文以西南财经大学学士学位论文为样例,围绕自动化测试系统设计与实现展开,涵盖Django框架、数据爬取、人脸识别等关键知识,适合用于毕业论文选题参考、查重降重对照或测试开发入门学习。资源为单个docx文档,整体压缩包约30KB,内容包含完整的论文目录,从绪论、系统设计、系统实现到系统测试与评价、结果分析与讨论、总结与展望共六章。论文详细介绍了总体架构、模块设计、数据库设计,并重点讲解requests库模拟HTTP请求、Scrapy框架数据爬取、Tesseract OCR图像文本识别以及Face_recognition人脸验证功能的实现思路,系统测试与结果分析部分也具有一定的实践参考价值。目前已有两百六十一人学习下载。文档体量虽小,但结构完整,对于需要快速理解自动化测试系统论文框架、梳理技术栈或寻找写作思路的读者,是一份实用且可复用的参考资料。
1. 自动化测试系统为什么在 Python 这里收敛
版本迭代一到回归阶段,手工点测的用例量会迅速压垮节奏:改一个登录逻辑,周边模块都要重新验证。多数团队缺的不是自动化技术,而是一套能把用例组织、数据执行和结果反馈串起来的系统,基于 Python 语言的自动化测试系统正好是组装成本最低的路线。
这类系统的核心不是某一款测试框架,而是用 pytest 做执行引擎,让 fixture 管理环境、yaml 承载测试数据、插件产出报告,形成从「写用例」到「看结果」的完整链路,解决回归效率低、失败现场难还原、用例规模变大后无法筛选和并行这三类问题。
内容按选型、目录分层、数据驱动、报告与并行推进,适合要从零搭测试系统、或想把脚本整理成体系的测试开发。命令和参数可直接复制,不要求先精通 python 基础语法,跑通 pytest 就能跟上。
2. Python 自动化测试系统的分层设计与选型:先把结构立住
自动化项目死在半年后的情况很常见:用例堆在同一个文件里,接口字段一改,断言跟着全局爆掉。活得久的项目往往先做两件事:选一个能扩展的执行引擎,定一套谁都不能乱进的目录边界。
2.1 执行引擎选 pytest 的三个理由
Python 生态里可选的测试框架不少,常见做法是在 pytest、unittest、Robot Framework 三者中选一个。unittest 是标准库自带,但它把用例强制组织成 TestCase 类,数据驱动还要靠 ddt 之类的补丁写法;Robot Framework 的关键字语法对非开发同事友好,可一旦涉及复杂断言、循环和异常处理,写起来比直接写 Python 绕得多。pytest 胜出是因为三点:
第一,断言直接用原生 assert,失败信息自动展示两侧实际值,不需要记 assertEqual、assertTrue 这一套 API;第二,fixture 和插件机制成熟,报告、并行、重试、执行顺序都能靠插件补齐,不用自己造轮子;第三,三方库绑定最全,requests、selenium、playwright 都有官方或社区维护的 pytest 插件,接入成本趋近于零。对刚接触 python 的测试同事来说,pytest 的函数式写法也比 unittest 的类继承更容易上手,这是选型里不能忽略的软性理由。
| 对比项 | pytest | unittest | Robot Framework |
|---|---|---|---|
| 用例写法 | 普通函数即可 | 必须继承 TestCase | 关键字表格 |
| 断言方式 | assert 原生表达式 | assertEqual 等 API | Should Be Equal 关键字 |
| 数据驱动 | parametrize 内置 | 依赖 ddt 或自写 | 模板关键字 |
| 报告与并行 | 插件生态完整 | 基本靠自写 | 自带报告,扩展有限 |
| 适合人群 | 测试开发与开发 | 习惯标准库的团队 | 偏业务、代码量少的团队 |
从维护角度看,执行引擎一旦定了,后期更换成本很高。选型结论落在 pytest 上,不是因为它绝对最好,而是因为小团队从零起步时,它的学习曲线和扩展成本都在最低点。
2.2 用例层、数据层、执行层的三层边界
不少团队把「测试系统」理解成「一堆测试文件」,这是一个常见误解。可维护的自动化测试系统在结构上会切成三层,每个目录只承担一个职责:
用例层(cases)只描述「测什么」,一个函数就是一条业务验证逻辑,断言写在用例里,但具体测试数据不写在用例里;数据层(data 与 config)把「用什么数据测」外置成 yaml 文件,同一套用例换环境、换数据不需要改代码;执行层(core)提供公共能力,包括 HTTP 请求封装、日志、公共断言和截图工具。如果后期需要图形入口,可以在执行层之上再包一层 flet 或 FastAPI 面板,但用例和执行核心不要碰 GUI。
依赖方向必须是单向的:cases 引用 core 和 data,core 不能反向引用 cases。这样做的收益很直接:接口字段变了,只需要改数据文件;框架或三方库升级,只需要改 core;新人接手,看目录就能知道什么东西该放哪里。数据外置优先选 yaml 而不是 Excel,原因是 yaml 可以进 git 做逐行 diff,Excel 改一个单元格就是整个文件变更,代码评审根本看不出改了什么。另外常见误用是把环境地址写死在用例里,换套测试环境就要全局替换一遍,这类配置必须归到 config 目录。
2.3 一套能直接落地的目录结构
下面这个结构是常见的起点,规模在几百条用例时不需要再扩展:
auto_test/ ├── config/ │ ├── pytest.ini # 执行参数与用例发现规则 │ └── settings.yaml # 环境地址、超时、账号等全局配置 ├── data/ │ └── login.yaml # 登录模块的用例数据 ├── cases/ │ ├── conftest.py # 本目录共享的 fixture 与 hooks │ └── test_login.py # 登录模块用例 ├── core/ │ ├── http_client.py # 请求封装:统一 header、超时、日志 │ ├── assert_util.py # 公共断言:状态码、字段、JSON 结构 │ └── logger.py # 日志格式与落盘配置 ├── report/ # HTML 报告、截图、日志产物 └── requirements.txt逻辑说明:pytest 会自动收集以 test_ 开头的文件,cases 目录是整个系统的用例入口;conftest.py 放在 cases 而不是根目录,是为了让 fixture 的作用域只影响用例层,core 里的公共代码不依赖 pytest 的夹具机制。config 和 data 分开,是因为环境配置属于执行环境,业务数据属于测试输入,混在一起会导致换环境时误改数据。
参数说明:如果用例文件想改成别的命名,比如 *_test.py,需要在 pytest.ini 里用 python_files 指定;目录名改不了,pytest 按 testpaths 配置扫描,建议把扫描范围固定在 cases,避免把 core 目录里带 test 前缀的辅助函数误收成用例。
3. 用 pytest 跑通 Python 自动化测试系统的最小闭环
结构定了之后,第一目标是跑通最小闭环:一条用例、一份数据文件、一次 pytest 命令,输出一份能看懂的结果。环境问题在这个阶段最容易劝退新人,所以先从 python 安装和解释器配置说起。
3.1 从 python 安装到解释器配置:venv、PyCharm 与 VSCode
Windows 上做 python 安装时,记得在安装向导第一页勾选 Add Python to PATH,否则命令行找不到 python;macOS 和 Linux 大多自带 python3,但版本可能偏旧,自动化系统建议用 3.10 以上的解释器。装完先验证,命令行执行 python --version,能输出版本号再继续。
依赖隔离是系统能迁移到 CI 的前提,常见做法是为每个项目建独立 venv:
python -m venv .venv source .venv/bin/activate # Windows 用 .venv\Scripts\activate python -m pip install --upgrade pip pip install pytest pytest-html pytest-xdist pytest-rerunfailures pyyaml requests逻辑说明:venv 会把依赖装进项目目录而不是全局 site-packages,同一台机器上不同项目各自持有互不干扰的包版本。PyCharm 配置 python 环境的位置在 Settings 里的 Project 的 Python Interpreter 页面,把解释器路径指到 .venv 即可;VSCode 配置 python 环境则是先装 Python 扩展,再通过命令面板里的 Python: Select Interpreter 选中同一个 venv。两者本质一致,只是入口不同。
参数说明:上面装的包就是后面所有章节的地基,pyyaml 用来读数据文件,requests 提供 HTTP 客户端,三个 pytest 插件分别对应报告、并行、重试。安装后可以用 pip list 确认版本号,避免后面出现「插件装了却找不到」的问题。
3.2 用 parametrize 加 yaml 把测试数据拆出去
如果把测试数据直接写在用例函数里,每加一条用例就要动一次代码,贡献门槛就被抬高了。把数据外置到 yaml 之后,偏业务的同事也能维护用例。先看数据文件:
login_success: case_name: "正常账号登录" payload: username: "tester01" password: "abc123" expect: code: 0 login_wrong_password: case_name: "密码错误" payload: username: "tester01" password: "bad-pass" expect: code: 1001对应的用例文件:
import pytest import yaml from core.http_client import HttpClient with open("data/login.yaml", "r", encoding="utf-8") as f: login_cases = yaml.safe_load(f) @pytest.mark.parametrize("case_key", login_cases.keys()) def test_login(case_key): case = login_cases[case_key] resp = HttpClient.post("/api/login", json=case["payload"]) assert resp["code"] == case["expect"]["code"]逻辑说明:safe_load 只解析 yaml 文本,不执行其中的任意对象,比直接 eval 安全;parametrize 把 case_key 当作参数传入,yaml 里有多少个 key,test_login 就扩展成多少条独立用例,失败时 pytest 输出的名字直接是 login_success 这种可读标识。expect 里后续可以继续加 msg、字段缺失之类的断言项,用例层不用跟着改。
参数说明:open 一定要带 encoding="utf-8",Windows 默认编码不是 utf-8,不带在某些机器上会抛 UnicodeDecodeError;parametrize 的第一个参数名必须和测试函数形参名一致,第二个参数是可迭代对象。若想报告里显示更友好的用例名,可以再给 parametrize 加 ids 参数,把 case_name 映射进去。
3.3 fixture 的 scope 参数:会话级还是函数级
登录态是测试系统里最常见的共享资源。每条用例都登录一次,用例一多耗时翻倍;全局只登录一次,又担心 token 过期。fixture 的 scope 就是用来在这两者之间做取舍的:
import pytest from core.http_client import HttpClient @pytest.fixture(scope="session") def base_url(): return "http://test.internal.example.com" @pytest.fixture(scope="function") def login_token(base_url): resp = HttpClient.post(base_url + "/api/login", json={"username": "tester01", "password": "abc123"}) token = resp["data"]["token"] yield token HttpClient.post(base_url + "/api/logout", headers={"Authorization": token})逻辑说明:yield 之前的语句在每条用例执行前运行,yield 之后的语句在用例结束后运行,这就是 pytest 的 teardown 写法,用来做登出、删除数据这类清理动作。login_token 的形参声明了 base_url,pytest 会按名字自动注入,不需要手动实例化,这也是 fixture 相对传统 setup/teardown 的优势。
参数说明:scope 支持四个级别,下表是常用参数的含义:
| scope | 创建时机 | 典型用途 |
|---|---|---|
| function | 每条用例前后各一次 | 临时数据清理、页面对象重置 |
| class | 每个测试类一次 | 类内共享的页面实例 |
| module | 每个用例文件一次 | 模块级环境准备 |
| session | 整个 pytest 进程一次 | 登录 token、数据库连接、全局配置 |
scope 不是越大越好。session 级 fixture 如果内部持有可变状态,在多进程并行时每个 worker 会各执行一次,第 4.3 节还会强调这个坑;反过来,模块级测试如果依赖独立数据,把 scope 从 module 改成 function 会让执行时间明显上涨。先按资源类型定作用域,再用实际耗时校准。
4. Python 自动化测试系统的报告、日志与并行执行
用例能跑只是起点,系统要进团队流程必须解决三件事:结果可读、失败可查、耗时可控。这一章把三个问题依次落地。
4.1 pytest-html 与 allure 的测试报告参数
pytest 默认的控制台输出在 CI 里不便于查看,常见做法是输出两条通道:pytest-html 生成单文件 HTML 报告,直接发给同事就能打开;allure 生成带历史趋势的站点式报告,适合长期观测。先看 pytest.ini 的整体参数:
[pytest] addopts = -ra --html=report/report.html --self-contained-html testpaths = cases markers = smoke: 冒烟用例 regression: 回归用例 slow: 耗时较长的用例参数说明:addopts 里的参数等价于命令行追加参数,-ra 在摘要区列出所有失败和跳过原因;--html 指定报告输出路径;--self-contained-html 把 CSS 和 JS 打进同一个 HTML 文件,单独拷走也能正常打开。testpaths 把扫描范围收紧到 cases,避免 pytest 去收集 core 目录里的辅助函数。markers 在这里做声明,声明之后再用 -m 筛选就不会产生 warning。
allure 的接入命令:
pip install allure-pytest pytest --alluredir=report/allure allure serve report/allure逻辑说明:--alluredir 把每次运行的原始结果落盘,allure serve 在本地起一个服务并自动打开浏览器。allure 命令行工具依赖 Java 运行时,团队机器上如果没有 Java,先用 pytest-html 顶住,不要被工具链卡住进度。
| 报告方案 | 产物形态 | 适合场景 | 注意点 |
|---|---|---|---|
| pytest-html | 单页 HTML | 轻量、外发给他人 | 无历史趋势 |
| allure-pytest | 站点目录 | 长期项目、看趋势 | 需要 Java 命令行 |
| --junitxml | JUnit XML | CI 平台解析 | 人不可读 |
4.2 用 pytest_runtest_makereport 抓失败现场
报告里只有「断言失败」四个字是不够的,排查问题需要页面截图、请求参数和响应体。pytest 的 hook 机制给了一个标准挂载点,所有钩子写在 conftest.py 里即可生效:
import time import logging from pathlib import Path import pytest logger = logging.getLogger("auto_test") @pytest.hookimpl(hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield report = outcome.get_result() if report.when == "call" and report.failed: shot = Path("report/screenshots") / \ f"{item.name}_{time.strftime('%Y%m%d_%H%M%S')}.png" shot.parent.mkdir(parents=True, exist_ok=True) driver = item.funcargs.get("driver") if driver is not None: driver.screenshot(str(shot)) logger.error("用例失败: %s, 截图: %s", item.name, shot)逻辑说明:hookwrapper=True 让外层函数先执行,yield 之后才能拿到内层 hook 的执行结果,这是为了同时覆盖 setup、call、teardown 三个阶段的 report。report.when == "call" 过滤出真正的用例执行体,避免 setup 阶段失败时重复处理;item.funcargs 可以拿到该用例已构造的所有 fixture,用 get("driver") 而不是直接下标,是为没有 driver 的纯接口用例准备的。
参数说明:screenshot 这里是通用方法名,实际项目对应 selenium 的 save_screenshot 或 playwright 的 page.screenshot,名称不同但挂载点一致。日志用 logging 而不是 print,原因是自动化测试系统的日志要能按级别过滤,排障时只关注 ERROR,而不是在几千行 stdout 里翻。若要把截图挂到 HTML 报告里,需要在 report 对象上追加 report.extra,pytest-html 会自动渲染。
注意:pytest_runtest_makereport 在所有 conftest.py 中都会生效,如果 core 目录也被扫描,hook 会被执行两次;保持 testpaths 收窄即可避免。
4.3 xdist 多进程并行:python 多进程 worker 的调度与坑
用例量到几百条之后,串行执行时间会涨到无法接受。pytest-xdist 的并行本质是 python 多进程:主进程把用例分发到多个 worker,每个 worker 独立执行分配到的那部分用例。
pytest -n 4 --dist loadscope pytest -n auto --dist loadscope逻辑说明:第一条命令固定开 4 个 worker,适合已知机器规格的固定环境;第二条命令由 pytest-xdist 根据主机 CPU 核数自动计算 worker 数量,适合配置不固定的开发机。
参数说明:-n 4 的数字按需调整,接口测试大多属于 I/O 密集,worker 数可以放到核数的两倍;计算密集型的用例保持核数即可,具体用哪一档,拿一次完整回归的总耗时来对比决定。--dist loadscope 让同一模块的用例尽量进入同一个 worker,避免共享的模块级 fixture 在多个 worker 里被重复初始化。
xdist 模式下的行为差异和串行不同,最常见的坑有两个。其一,session 级 fixture 在每个 worker 里都会执行一次,如果 fixture 里初始化了数据库连接,并行 4 个进程就多出 4 份连接,缓解办法是让 session 级 fixture 保持幂等,或者把重量级初始化降到 module 级。其二,测试数据如果存在共享文件里,并行写同一个文件会互相覆盖,用例之间要避免共享写文件,或者给文件名加 worker 标识。
注意:xdist 不保证用例按书写顺序执行,依赖执行顺序的用例要显式加 pytest-ordering 插件或用独立模块隔离,靠命名顺序赌正确性是定时炸弹。
5. 从能跑到跑稳:Python 自动化测试的标记、重试与结果统计
系统的稳定性问题很少来自跑不起来,更多来自跑飞了没人知道。先把用例集按风险切成几组,再决定哪些失败值得重试,最后统一统计口径,这套系统才敢放开每天在 CI 里跑。
5.1 用 -m 表达式把用例集切成冒烟、回归与慢速
pytest.ini 里已经声明了 smoke、regression、slow 三个 marker,用例上只用装饰器挂标签,跑的时候按表达式切片:
pytest -m "smoke" pytest -m "regression and not slow" pytest -m "not slow"逻辑说明:-m 后面接的是一个布尔表达式,and、or、not 都可用。冒烟集要求 5 分钟内跑完,回归集排除慢速用例在白天执行,慢速用例固定留给夜间任务,全部用同一套标记切开,不需要维护多个工程。参数说明:标记名必须在 pytest.ini 的 markers 里先声明,不声明的标记在严格模式下会被 pytest 警告甚至拒绝运行。
5.2 重试参数:只对能重试的失败重试
重试是把双刃剑。对网络抖动、服务重启这类瞬时失败,重试能救回来;对代码缺陷导致的失败,重试只会掩盖问题,让回归结果失去可信度。稳妥做法是用 --only-rerun 限制异常类型:
pytest --reruns 2 --reruns-delay 1 \ --only-rerun "ConnectionError|AssertionError"逻辑说明:把可重试的异常范围显式列出来,正则匹配异常类名,匹配到的才触发重试。参数说明:--reruns 是单个用例最大重试次数;--reruns-delay 是重试间隔,单位秒,给下游服务一点恢复时间。AssertionError 在数据驱动用例里值得重试,因为数据文件刚提交时偶发脏数据;但 KeyError、TypeError 这类代码缺陷绝对不能重试,一旦出现,第一优先级是查代码而不是等重试。
5.3 统计口径与 --durations 的持续观测
结果统计要先把口径说清楚:重试后通过的用例,按通过计入整体通过率,但 pytest-html 的报告里会保留 rerun 记录,方便事后区分「一次通过」和「重试通过」。项目里通常同时输出 JUnit XML 给 CI 平台,避免不同平台各自的统计方式算出不一样的数字:
pytest --durations 10 --junitxml=report/junit.xml逻辑说明:--junitxml 输出的 XML 由 CI 平台解析,--durations 的结果打印在控制台末尾,两者互不干扰。参数说明:--durations 10 在运行结束后列出耗时最长的 10 条用例,这是定位性能劣化的最快入口。当系统稳定运行两周后,用 python 的数据分析与可视化能力处理 report 目录里的历史产物,把每次运行的耗时、失败模块做成趋势曲线,能比看单次通过率更早发现接口响应劣化的苗头。把 --durations 的 top10 固化到 CI 日志末尾,每次跑完自动对比名次变化,只要发现连跑三天都在前三位出现的用例,就值得单独做接口耗时分析。
本文还有配套的精品资源,点击获取