pytest是UI自动化框架的骨架,通过fixture管理浏览器启停与登录态、钩子统一捕获失败上下文、PO模式解耦操作与断言、webdriver-manager适配CI环境,确保200+用例仍可快速定位问题根源。

pytest 不是“用来跑测试的工具”,而是整个 UI 自动化框架的骨架。它决定你能不能干净地管理浏览器、复用登录态、隔离失败用例、生成可读报告——这些不是附加功能,而是框架能否活过三个月的关键。
为什么不能直接写 test_login.py 就完事?
很多人卡在第一步:写了几个 test_*.py 文件,跑通了,就以为框架搭好了。结果两周后发现:driver 全局变量到处传、每个用例都重复 webdriver.Chrome()、失败后浏览器没关、截图堆满桌面却找不到对应日志。这不是测试写得不好,是缺少约束机制。
真正要解决的,是“谁负责启停浏览器”“谁管登录态缓存”“失败时怎么留证据”。这些必须由 pytest 的 fixture 承担,而不是靠人肉复制粘贴。
-
fixture必须覆盖scope="session"(整个测试轮次只启一次浏览器)和scope="function"(每个用例前后自动清理)两个层级 - 不要在测试函数里直接调用
driver.quit(),交给yield后的 teardown 逻辑 - 截图、页面源码、URL、时间戳这些上下文信息,要在
pytest_runtest_makereport钩子中统一捕获,而不是每个assert后手动driver.save_screenshot()
Page 类怎么写才不算白写?
PO 模式不是“把 find_element 拆到另一个文件里”就叫分层。真正起作用的,是让页面操作与断言解耦,且能自然承载等待逻辑。
比如一个抽奖按钮,不能只定义 self.driver.find_element(By.ID, "lottery-btn"),而应封装成:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
立即学习“Python免费学习笔记(深入)”;
def click_lottery_button(self):
btn = self.wait.until(EC.element_to_be_clickable((By.ID, "lottery-btn")))
btn.click()
return self.wait.until(EC.presence_of_element_located((By.CLASS_NAME, "result-popup")))
这样做的好处是:
- 等待策略内聚在页面类里,测试用例不用关心“等多久”
- 返回值是下一个页面对象(如
ResultPage),形成链式调用,避免用例里出现time.sleep(2) - 所有定位器集中管理,改 ID 时只需改一处
环境配置和驱动管理最容易被跳过的坑
本地跑通 ≠ CI 上能跑。很多团队在 Jenkins 或 GitLab CI 上第一次执行就失败,原因往往出在三处:
- 硬编码
ChromeDriver路径 —— 改用webdriver-manager自动匹配版本:from webdriver_manager.chrome import ChromeDriverManager - 没处理 headless 模式 —— Linux 环境无图形界面,必须加参数:
options.add_argument("--headless=new") - 环境变量混用 ——
.env文件只放敏感配置(如账号密码),config.py放 URL、超时时间等可公开参数,且用os.getenv("TEST_ENV", "staging")切换
真正的难点不在“怎么写第一个测试”,而在“当用例涨到 200+ 时,是否还能快速定位是脚本问题、环境问题还是被测系统问题”。这取决于 fixture 的颗粒度、页面类的职责边界、以及错误上下文是否自动附带。框架不会自动变健壮,它只反映你对失败场景的预判深度。

















