
简介一份基于Python语言的自动化测试系统毕业论文文档面向专科与本科毕业生、自动化测试初学者及需要毕业设计参考的学生可直接用于理解自动化测试从理论到落地的完整路径。内容围绕自动化测试系统的设计与实现展开系统阐述绪论、系统设计、系统实现、系统测试与评价、结果分析及总结展望并融入Python、Django框架、数据爬取和人脸识别等关键技术。包体为单个docx文档压缩包大小约30KB结构简洁便于直接阅读和二次修改。文档中详细说明了requests库模拟HTTP请求、Scrapy框架爬取测试数据、Tesseract OCR识别图像文本以及Face_recognition库实现人脸识别等核心实现同时对测试用例管理、测试执行、结果分析和报告生成等模块进行了设计说明可帮助读者梳理论文框架与实现思路。目前已有261人学习适合正在撰写自动化测试方向论文或希望了解Python测试技术实际应用的学生参考。1. 自动化测试系统的边界不是把手工点一遍换成脚本点一遍手工测试真正贵的不是“点”而是回归。上线前全量冒烟要占掉多少人天、改一次公共模块要连带验证多少个历史用例这些成本在项目迭代到第三个月之后会迅速压过功能开发的投入。用 Python 做自动化测试系统核心价值不在“自动执行”而在把用例编写、执行调度、结果判定、报告生成串成一条可重复的流水线让测试代码像业务代码一样有版本、有组织、能被复用。这篇内容要拆的是这样一个系统的完整骨架从四模块架构和数据库设计开始落到 pytest Selenium 的脚本组织方式再讲 Django 后台、数据爬取和人脸识别模块如何接入测试流程最后收在 Jenkins 集成和排错技巧上。适合正在用 unittest 或 pytest 写零星脚本、想把它升级成正式系统的测试开发也适合做类似选题时需要一套可复现方案的毕业生。2. 系统总体架构与数据库设计先定边界再写代码自动化测试系统最容易犯的错误是一上来就写脚本写到一半发现用例多了没法管理、结果没法回溯、报告没人看。论文里给出的四个模块——测试用例管理、测试执行、测试结果分析、测试报告生成——本质上是在给测试工作划边界。用例管理解决“测什么”执行模块解决“怎么跑”结果分析解决“跑完怎么看”报告生成解决“怎么让别人看”。2.1 四模块职责划分四个模块的依赖关系是单向的。用例管理模块向下游提供用例数据和套件组织方式执行模块读取这些数据后调度测试进程执行过程中产生的原始结果交给分析模块做统计分析结果再由报告模块渲染输出。模块间不能交叉调用否则后期改一个模块会牵动整条链路。用例管理维护用例的增删改查、标签、优先级、套件归属支持从 Excel 或 CSV 批量导入。常见做法是用一套 Web 界面操作数据落在数据库里执行端通过接口拉取。测试执行负责加载用例、初始化测试数据、按顺序或按依赖关系执行收集通过率、失败原因、执行耗时。多线程或分布式执行在这里接入。结果分析对执行记录做聚合统计比如按模块统计失败率、按时间段统计稳定性、定位高频失败用例。报告生成把统计结果渲染成 HTML 或 PDF支持自定义模板能自动附带失败截图和堆栈信息。2.2 核心表结构与建表 SQL数据库设计方面SQLite 适合单机执行场景部署简单、无需单独维护服务如果系统要支持多人协作和 Web 端同时读写换成 MySQL 或 PostgreSQL字段设计逻辑是一致的。核心是四张表测试套件表、测试用例表、执行记录表、报告表。CREATE TABLE test_suite ( suite_id INTEGER PRIMARY KEY AUTOINCREMENT, suite_name VARCHAR(128) NOT NULL UNIQUE, description TEXT, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE test_case ( case_id INTEGER PRIMARY KEY AUTOINCREMENT, suite_id INTEGER NOT NULL, case_name VARCHAR(128) NOT NULL, steps TEXT, expect_result TEXT, priority INTEGER DEFAULT 3, tags VARCHAR(255), create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (suite_id) REFERENCES test_suite(suite_id) ); CREATE TABLE test_execution ( exec_id INTEGER PRIMARY KEY AUTOINCREMENT, case_id INTEGER NOT NULL, status VARCHAR(16) NOT NULL, duration_ms INTEGER, error_message TEXT, screenshot TEXT, exec_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (case_id) REFERENCES test_case(case_id) ); CREATE TABLE test_report ( report_id INTEGER PRIMARY KEY AUTOINCREMENT, exec_start TIMESTAMP, exec_end TIMESTAMP, total_count INTEGER, pass_count INTEGER, fail_count INTEGER, skip_count INTEGER, report_path TEXT, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP );建表逻辑里几个关键点test_case.steps不用 JSON用 TEXT 存纯文本或按行分隔的步骤描述这样在 SQLite 里查询和导出都方便真要结构化可以后续再解析priority用整数不用字符串1 到 5 级排序和过滤效率更高test_execution和test_report都带时间戳后续做趋势分析直接按时间聚合。关联关系上套件与用例是一对多用例与执行记录是一对多。在suite_id和case_id上建索引否则执行记录表量级上去之后按用例查历史结果会明显变慢。主键用自增整数够用不需要 UUID这套系统的数据量级远没到分布式 ID 的瓶颈。3. 测试框架选型与脚本组织pytest 是底座PO 模式是骨架框架选型决定了脚本的写法和维护成本。很多人纠结 unittest 还是 pytest其实从 3 开始pytest 已经内置了对 unittest 用例的兼容可以直接跑所以新项目没有理由再从 unittest 起步。3.1 主流框架对比框架断言风格参数化Fixture插件生态适用场景unittest继承 TestCase 的 assert 方法无原生支持需外部库setUp/tearDown较少老项目兼容、标准库依赖pytest原生 assert 重写报错内置 parametrizefixture 机制作用域可控非常丰富新项目首选接口/UI/单元全覆盖Robot Framework关键字表驱动数据表驱动Suite/Test 级有但依赖 Java 生态业务人员维护用例的场景选 pytest 的另外三个理由fixture 的scope参数可以控制 session/module/class/function 四个级别的复用能省掉大量重复初始化的代码parametrize直接解决数据驱动问题不用自己写循环插件生态里有pytest-html、pytest-xdist、pytest-rerunfailures覆盖报告、并行、重试三个高频需求。3.2 页面对象模式的落地写法页面对象模式Page Object Model的核心目的是把页面元素定位和业务操作分离。业务层不出现find_element这类调用只调用页面对象的方法这样页面结构变了只需要改对应页面对象。# base_page.py from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class BasePage: def __init__(self, driver: webdriver.Remote): self.driver driver self.wait WebDriverWait(driver, timeout10) def click(self, locator: tuple): # 显式等待元素可点击避免网络慢导致的 NoSuchElementException self.wait.until(EC.element_to_be_clickable(locator)).click() def input_text(self, locator: tuple, text: str): element self.wait.until(EC.visibility_of_element_located(locator)) element.clear() # 分次输入比 send_keys 更稳定避免中文输入丢字符 if text: element.send_keys(text) def get_text(self, locator: tuple) - str: return self.wait.until(EC.visibility_of_element_located(locator)).text# login_page.py from selenium.webdriver.common.by import By from base_page import BasePage class LoginPage(BasePage): # 元素定位集中定义页面结构变化只改这里 username_input (By.ID, username) password_input (By.ID, password) login_button (By.CSS_SELECTOR, button[typesubmit]) error_msg (By.CLASS_NAME, error-tip) def login(self, username: str, password: str): self.input_text(self.username_input, username) self.input_text(self.password_input, password) self.click(self.login_button) def get_error_message(self) - str: return self.get_text(self.error_msg)BasePage里click和input_text都用了显式等待而不是time.sleep区别在于等待条件是元素状态而不是固定时间。固定等待在 CI 机器负载高时会误报负载低时又浪费时间显式等待只在条件满足时继续执行默认 10 秒超时超时会抛TimeoutException日志里能看到具体是哪个元素没出现。By.CSS_SELECTOR定位优先比 XPath 稳定且快只有 CSS 表达不了复杂层级时才用 XPath。3.3 数据驱动与关键字驱动的差异数据驱动适合接口测试和表单类用例pytest 的parametrize是最轻量的实现方式。在test_login.py中把用户名、密码、预期结果放在外部 CSV 里用pytest.mark.parametrize注入新增一组数据不用改代码。import csv import pytest from login_page import LoginPage def load_credentials(): cases [] with open(testdata/login_data.csv, encodingutf-8-sig) as f: reader csv.DictReader(f) for row in reader: # 跳过被注释掉的用例便于临时禁用 if row[enabled].lower() true: cases.append((row[username], row[password], row[expected])) return cases pytest.mark.parametrize(username,password,expected, load_credentials()) def test_login_cases(username, password, expected, driver): page LoginPage(driver) page.login(username, password) if expected success: assert dashboard in driver.current_url else: assert page.get_error_message() expectedencodingutf-8-sig会去掉 BOM 头否则 Excel 保存的 CSV 会在第一列字段名里带\ufeff导致参数名不匹配。这里的driver是 fixture通常放在conftest.py里配置 session 级初始化每个测试函数接收同一个浏览器实例。关键字驱动比数据驱动多一层抽象把测试步骤抽象成“关键字 参数”由执行引擎解释运行。比如步骤login | admin | 123456引擎根据关键字login找到对应函数并传入两个参数。优点是业务人员可以用 Excel 写用例缺点是 Debug 困难报错堆栈定位不到具体代码行。对这个项目来说pytest 的数据驱动已经覆盖大部分场景关键字驱动适合测试团队没有编程能力的情况不建议一上来就做。4. Django 后端接入与数据采集、人脸识别模块实现论文的摘要里把 Django、数据爬取、人脸识别列为关键知识点这三块在自动化测试系统里分别对应后台服务、测试数据准备、图像验证三个环节。Django 承担用例管理和报告展示的后台接口爬虫解决测试数据来源人脸识别用于图像类接口的自动化断言。4.1 Django 后台服务与接口设计Django 作为后端服务核心是把数据库里的用例和执行结果暴露成 REST 接口前端界面或测试执行机通过 HTTP 调用。搭建时用 Django REST Framework序列化器直接映射模型不必手写 JSON 拼接。# apps/case/serializers.py from rest_framework import serializers from .models import TestCase, TestSuite class TestCaseSerializer(serializers.ModelSerializer): # 嵌套返回套件名称避免前端拿 ID 再查一次 suite_name serializers.CharField(sourcesuite.suite_name, read_onlyTrue) class Meta: model TestCase fields [case_id, case_name, suite_name, priority, tags]# apps/case/views.py from rest_framework.viewsets import ModelViewSet from rest_framework.permissions import IsAuthenticated from .models import TestCase from .serializers import TestCaseSerializer class TestCaseViewSet(ModelViewSet): queryset TestCase.objects.select_related(suite).all() serializer_class TestCaseSerializer permission_classes [IsAuthenticated] def get_queryset(self): # 支持按优先级和标签过滤让执行端可以按条件拉取用例 queryset super().get_queryset() priority self.request.query_params.get(priority) tag self.request.query_params.get(tag) if priority: queryset queryset.filter(prioritypriority) if tag: queryset queryset.filter(tags__icontainstag) return querysetselect_related(suite)解决 N1 查询问题不加它会为每条用例单独查一次套件表用例多时接口明显变慢加了之后一次性JOIN查出。IContains对应 SQL 里的LIKE做标签模糊过滤够用。IsAuthenticated权限类要求所有接口带 Token避免内网测试平台被人随意改数据。4.2 requests 与 Scrapy 在测试数据准备中的应用自动化测试系统里数据爬取不是业务功能而是为了构造测试数据。比如需要批量生成不同用户名、手机号、地址的注册用例手工造数据效率太低从公开页面抓取再清洗是常见做法。import requests from bs4 import BeautifulSoup def fetch_test_names(count100): url https://example.com/api/names params {format: json, count: count} resp requests.get(url, paramsparams, timeout10) # 显式校验状态码避免页面返回错误页面时被解析成空数据 resp.raise_for_status() data resp.json() return [item[name] for item in data[results]]raise_for_status()很关键不调用的话接口返回 500 时resp.json()会拿到错误页面的 HTML解析时报错信息不直观。timeout参数必须设置否则某个请求挂住会让整个测试执行卡死。批量生成的数据存在测试库或 CSV 里用 pytest 的parametrize加载即可。爬虫任务量再大一点单线程 requests 就不够了换 Scrapy 做并发抓取。Scrapy 的Request回调机制天然适合多级页面采集比如先抓列表页拿详情链接再并发抓详情页字段。注意抓取频率设置DOWNLOAD_DELAY 0.5单位是秒控制单请求间隔避免对目标站点造成压力。测试数据爬取只做合法公开数据的采集不碰登录态和隐私字段这个边界要守住。4.3 Tesseract OCR 与 Face_recognition 的图像断言图像类测试是 UI 自动化的难点。验证码识别、图片中的文字校验、人脸登录模块的返回结果这些用find_element拿不到文本内容需要 OCR 或人脸特征比对。import pytesseract from PIL import Image def extract_text_from_image(image_path: str) - str: 识别截图中的文本用于校验页面上渲染的公告或协议内容。 with Image.open(image_path) as img: # gray 预处理能显著提高 OCR 准确率彩色背景会干扰文字分割 gray img.convert(L) text pytesseract.image_to_string(gray, langchi_simeng) return .join(text.split())convert(L)把图像转成灰度去掉彩色干扰langchi_simeng同时加载中文简体与英文语言包语言包要用 Tesseract 的language管理命令单独安装不是装完 Tesseract 就有。注意image_to_string返回的内容含大量换行和空格.join(text.split())去掉空白字符后再做断言匹配否则经常因为换行位置不同而误判失败。人脸识别模块用于测试带人脸登录功能的系统。face_recognition库封装了 dlib 的人脸特征提取接口很简单但要注意模型文件和计算资源的消耗。import face_recognition def verify_face(image_path: str, known_face_path: str, tolerance: float 0.6) - bool: # 加载样本图片并提取 128 维人脸特征向量 known_image face_recognition.load_image_file(known_face_path) known_encoding face_recognition.face_encodings(known_image) # 有人脸才继续比对图中无人脸直接返回 False避免空列表索引报错 if not known_encoding: return False test_image face_recognition.load_image_file(image_path) test_encodings face_recognition.face_encodings(test_image) for encoding in test_encodings: # compare_faces 返回布尔列表tolerance 越小匹配越严格 matches face_recognition.compare_faces([known_encoding[0]], encoding, tolerancetolerance) if any(matches): return True return Falsetolerance是误判率开关默认 0.6 对一般场景够用安全要求高的场景调到 0.4 以下但人脸角度和光线变化大时会导致大量漏报自动化测试里通常先确认测试图片是正脸且光照均匀。face_recognition首次运行会加载约 150MB 的模型到内存并发执行时不要每张图都重新加载模型放在模块级或 fixture 的 session 作用域里复用。5. 执行调度、CI 集成与高频排错技巧系统开发完成后落地效果取决于执行链路是否稳定。这一章讲命令行参数管理、并发执行、Jenkins 集成以及三个最容易踩的坑。5.1 命令行参数与并行执行测试执行机通过命令行参数控制要跑的用例范围和环境而不是改代码里的配置。用 pytest 的addoption扩展自定义参数。# conftest.py def pytest_addoption(parser): parser.addoption(--env, actionstore, defaulttest, helptest/staging/prod) parser.addoption(--suite, actionstore, default, help只执行指定套件) pytest.fixture(scopesession) def env(request): return request.config.getoption(--env) pytest.fixture(scopesession) def base_url(env): # 不同环境映射不同地址参数从环境变量读取避免敏感信息写死在代码里 return { test: http://test.example.com, staging: os.environ.get(STAGING_URL), }.get(env, http://localhost:8000)执行命令示例pytest -n 4 --distloadscope --envstaging --suitelogin \ --htmlreport.html --self-contained-html --maxfail5-n 4是 pytest-xdist 的并行数--distloadscope按模块分配进程同一个测试模块里的用例不会分散到不同进程避免共享状态的冲突。--self-contained-html把 CSS 和 JS 内嵌进 HTML 报告单独发文件给别人看时样式不会丢。--maxfail5在连续失败 5 条后停止配合 CI 快速失败策略省得等全部跑完才意识到环境挂了。5.2 Jenkins Pipeline 集成自动化测试要真正产生价值必须跑在 CI 里提交代码自动触发测试任务。Jenkins Pipeline 脚本在项目根目录放Jenkinsfile把构建、测试、报告归档串起来。pipeline { agent any environment { PYTHON_ENV staging } stages { stage(Install Dependencies) { steps { sh python3 -m venv venv . venv/bin/activate pip install -r requirements.txt } } stage(Run Tests) { steps { sh . venv/bin/activate pytest -n 4 --env${PYTHON_ENV} --htmlreport.html --self-contained-html --junitxmlresult.xml } } stage(Archive Report) { steps { archiveArtifacts artifacts: report.html, allowEmptyArchive: true junit result.xml } } } }junit指令会把 pytest 生成的 JUnit XML 解析成趋势图和失败列表在 Jenkins 界面上直接看到最近 50 次执行的通过率曲线。allowEmptyArchive: true是防止测试全部跳过时没有报告文件导致构建标记失败。虚拟环境用python3 -m venv而非系统 Python避免跑到环境里其他安装的包版本。5.3 高频问题排查现象根因处理方式脚本本地能跑Jenkins 上报元素找不到服务器上浏览器版本与 Selenium 驱动不匹配用 Selenium Manager 自动匹配驱动版本或固定浏览器和驱动版本组合并行执行时用例互相影响共享了同一个测试账号或同一份测试数据每个 worker 使用独立账号测试数据按 worker 编号隔离OCR 识别结果总是不对截图里文字带抗锯齿或背景复杂做放大和灰度预处理必要时先做二值化再交给 Tesseract数据库里执行记录膨胀很快每次跑完保留全量明细写定时任务清理 30 天前的记录报告表保留最近 100 条即可最后一个比较隐蔽的问题pytest-xdist下每个 worker 单独跑 fixture 的 session 作用域如果初始化测试数据的 fixture 在多个模块里定义每个 worker 都执行一次重复数据会导致断言失败。解决办法是让初始化操作幂等比如先删除再插入或者在执行入口处加一个分布式锁。对这套系统用 SQLite 时把数据库改成 WAL 模式也能减少并发写入时的锁冲突import sqlite3 conn sqlite3.connect(test_data.db) conn.execute(PRAGMA journal_modeWAL) conn.execute(PRAGMA synchronousNORMAL)WAL 模式在读多写少的场景下能明显降低同一时间多个 worker 操作数据库时的database is locked报错频率synchronousNORMAL在可容忍断电丢失最近一次提交的前提下减少同步开销自动化测试数据丢失一点可以重新生成性能收益更值得。本文还有配套的精品资源点击获取