
这两年自动化测试的热度一直没降过但真正做过UI自动化的人几乎都遇到过同一个问题脚本写起来快维护起来痛。元素一改、弹窗一飘、接口返回一波动用例就开始成片失败最后测试框架反而成了团队的运维负担。随着大模型能力逐步成熟AI 与自动化测试的结合正在从“概念讨论”走向“真实落地”。本文不聊虚的直接围绕一个可运行的 AI 自动化测试项目从环境搭建、核心原理、代码实现到问题排查完整走一遍重点演示 AI 如何辅助定位元素、生成用例、处理非预期弹窗以及如何把传统自动化测试框架改造成具备一定自我修复能力的智能测试脚本。如果你目前是 0 基础入门或者已经在写 Selenium / Playwright 但想进一步了解 AI 在测试中的落地方式这篇文章都适合。1. AI与自动化测试为什么要关注这个方向1.1 传统自动化测试的痛点自动化测试解决的核心问题是“回归效率”。手工回归一个核心流程可能要 30 分钟自动化脚本只需要几分钟。但很多团队在落地之后发现自动化测试并没有想象中“省心”。举一个很常见的场景登录按钮的class从btn-login改成了btn-submit。这个改动对用户毫无影响但自动化脚本会立刻报错因为原来的定位器失效了。再比如页面中突然出现一个非预期弹窗把输入框挡住了脚本点击失败测试直接中断。这一类问题的本质是传统自动化测试的定位器是“硬编码”的脚本本身不具备根据页面上下文智能推断元素位置的能力。任何前端调整都可能需要测试人员手动维护脚本。1.2 AI 能在自动化测试中做什么AI 在自动化测试中的应用并不是让机器完全代替测试设计而是把重复性、机械性、高维护成本的部分交给模型来处理。目前比较务实的应用方向包括智能元素定位根据页面 HTML 结构或截图由大模型推荐稳定的定位器。测试用例生成根据接口文档或用户操作描述生成标准测试用例和断言逻辑。失败原因分析测试失败时自动分析日志、截图给出可能的原因和修复建议。动态等待与自愈元素定位失败时自动尝试多种备选选择器。非预期弹窗处理识别页面中出现的无关弹窗并自动关闭。这些能力并不需要模型掌握全部业务知识而是通过合理的提示词Prompt设计和工程封装把一个原本需要人工判断的过程变成自动化流程。1.3 读者需要掌握哪些基础开始本文实战之前建议具备以下基础Python 基础语法包括函数、类、装饰器。对 HTTP 请求和 JSON 数据结构有基本了解。有简单的自动化测试概念比如 Selenium 或 Playwright 的基本用法。有大模型 API 的基本认知不要求了解复杂的大模型原理。如果以上基础还没完全掌握也不影响阅读。本文会尽可能把每一步解释清楚你可以边看边查跟着代码写一遍是最快的理解方式。2. 环境准备与工具选型2.1 环境版本说明不同环境下安装细节会有差异建议以你自己的系统实际为准。本文示例使用以下环境组件版本/说明操作系统Windows 10/11 或 macOSPython3.10 或更高版本浏览器Chrome最新稳定版自动化库Playwright 1.40Web框架Flask 3.x用于构建被测演示项目AI能力通过 OpenAI 兼容接口或国内大模型 API 调用如果你已经安装了 Python 3.8也可以运行但建议优先使用 3.10避免类型注解和语法兼容问题。2.2 为什么选择 Playwright目前主流的 Web 自动化库有 Selenium 和 Playwright。两者都能完成浏览器自动化但 Playwright 在以下几个方面更适合与 AI 结合内置等待机制更智能元素出现前自动等待。支持通过浏览器上下文快速模拟登录态。可以方便地截图并转成 Base64 传给大模型 API。定位器Locator设计更加工程化便于做二次封装。同时支持 Chromium、Firefox、WebKit。如果你之前一直使用 Selenium本文示例中的思路同样可以迁移到 Selenium 上核心逻辑并不冲突。2.3 创建虚拟环境并安装依赖建议为该项目单独创建虚拟环境避免污染系统 Python 环境。mkdir ai_web_test cd ai_web_test python -m venv venvWindows 激活虚拟环境venv\Scripts\activatemacOS / Linux 激活source venv/bin/activate接下来安装项目依赖pip install playwright flask requests playwright install chromium如果你在国内网络环境安装浏览器内核时如果下载过慢可以考虑配置 Playwright 的镜像源具体以你所在网络环境为准。这里不展开讲代理配置只提醒一句下载失败时优先检查网络然后检查 Playwright 与浏览器内核版本是否匹配。安装完成之后可以先写一个最小的 Playwright 脚本验证环境# quick_test.py from playwright.sync_api import sync_playwright with sync_playwright() as p: browser p.chromium.launch(headlessFalse) page browser.new_page() page.goto(https://www.baidu.com) print(page.title()) browser.close()运行python quick_test.py如果能看到浏览器打开并输出百度标题说明 Playwright 环境正常。3. 核心原理拆解3.1 自动化测试的基本流程无论是否引入 AI一个标准 UI 自动化测试用例都包含以下步骤打开目标页面。等待页面关键元素出现。执行用户操作输入、点击、选择。断言预期结果。测试结束输出报告。传统模式下第 2 步和第 3 步完全依赖测试人员提前写好的定位器。定位器的写法很多包括 ID、Name、Class、XPath、CSS 选择器。问题在于前端页面调整时定位器很容易失效。3.2 AI 智能定位的设计思路如果我们让 AI 参与定位思路可以调整成测试脚本给出一个“语义化”的目标描述例如“登录按钮”。脚本把当前页面的 HTML 片段或可见文本发送给大模型。大模型根据语义理解返回一组推荐的定位策略。测试框架按优先级依次尝试这些定位器直到成功。这样做的好处是如果前端只修改了少量 class 名称但按钮的文本内容仍然是“登录”AI 仍然可以通过文字内容定位到元素。定位器的稳定性大幅提升。3.3 提示词设计是关键大模型输出结果的质量很大程度上取决于提示词设计。一个不清晰的提示词可能返回大段解释文字而我们需要的是结构化 JSON。下面是一个最小化的提示词模板示例你是一名资深测试开发工程师。给定页面 HTML 片段和目标元素描述请返回一个 JSON 数组数组中每一项是一个候选定位器字段为 - type: css 或 xpath - value: 定位器表达式 要求 1. 优先使用 CSS 选择器。 2. 如果 HTML 片段不足请结合目标元素的文本内容给出建议。 3. 只输出 JSON不要输出解释。 HTML片段 {html_snippet} 目标元素 {element_desc}工程落地时可以把这段模板封装成函数统一管理。3.4 非预期弹窗的识别与处理非预期弹窗是 UI 自动化测试中非常常见的失败原因。这类弹窗往往不是当前用例关注的目标但它会遮挡页面元素导致点击失败。常规做法是维护一个“弹窗关闭选择器”列表在每一次关键操作之前先执行一次弹窗扫描。AI 的介入可以进一步提高识别能力当截图给到大模型后模型可以判断“当前页面是否有非业务弹窗”并返回关闭按钮的定位方式。实战项目中最快的切入方式是先做一个规则 选择器列表的方案后续再考虑接入 AI 视觉识别。4. 完整实战AI辅助UI自动化测试项目下面进入实战环节。为了避免依赖外部网站导致测试不稳定我们会先用 Flask 搭建一个带登录功能的演示网站再针对这个网站编写自动化测试。4.1 项目结构ai_web_test/ ├── app.py # Flask 被测应用 ├── ai_engine.py # AI 定位与智能分析模块 ├── pages.py # 页面操作封装 ├── conftest.py # pytest fixtures ├── test_login.py # 登录流程测试 └── requirements.txt4.2 创建被测应用我们用 Flask 写一个极简登录页面故意把按钮的 class 设置成动态样式用来模拟真实项目中前端频繁调整的场景。# app.py from flask import Flask, render_template_string, request, redirect app Flask(__name__) LOGIN_PAGE !DOCTYPE html html head titleAI自动化测试演示系统/title /head body h2欢迎登录/h2 form methodpost action/login label用户名/label input typetext idusername nameusername placeholder请输入用户名 / label密码/label input typepassword idpassword namepassword placeholder请输入密码 / button typesubmit classbtn-login-v2立即登录/button /form script // 模拟前端动态调整class会被随机修改 const btnMap [btn-login, btn-submit, btn-login-v2]; const btn document.querySelector(button[typesubmit]); btn.className btnMap[Math.floor(Math.random() * btnMap.length)]; /script /body /html WELCOME_PAGE !DOCTYPE html html headtitle登录成功/title/head body h2登录成功欢迎你/h2 p classwelcome-user{{ username }}/p /body /html app.route(/) def index(): return render_template_string(LOGIN_PAGE) app.route(/login, methods[POST]) def login(): username request.form.get(username) password request.form.get(password) if username and password: return render_template_string(WELCOME_PAGE, usernameusername) return redirect(/)运行这个应用python app.py浏览器访问http://127.0.0.1:5000你会看到登录页面。注意按钮的 class 会在btn-login、btn-submit、btn-login-v2之间随机切换。这模拟了前端频繁变动的场景。如果你的自动化脚本只写死了某一个 class刷新页面后就会失败。4.3 封装 AI 定位引擎接下来编写ai_engine.py。这个模块负责与兼容 OpenAI 格式的大模型接口交互根据页面 HTML 生成候选定位器。# ai_engine.py import json import requests API_URL https://api.openai.com/v1/chat/completions API_KEY your-api-key MODEL_NAME gpt-4o-mini SYSTEM_PROMPT 你是一名资深测试开发工程师。给定页面 HTML 片段和目标元素描述请返回一个 JSON 数组。 数组中每一项是一个候选定位器字段为 - type: css 或 xpath - value: 定位器表达式 要求 1. 优先使用 CSS 选择器并基于稳定的属性或文本内容。 2. 如果 HTML 片段不足请结合目标元素的文本内容给出建议。 3. 只输出 JSON不要输出任何解释。 def suggest_locators(html_snippet: str, element_desc: str) - list: 调用大模型 API返回候选定位器列表。 user_content fHTML片段\n{html_snippet}\n\n目标元素{element_desc} payload { model: MODEL_NAME, messages: [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_content} ], temperature: 0.2 } headers { Authorization: fBearer {API_KEY}, Content-Type: application/json } resp requests.post(API_URL, jsonpayload, headersheaders, timeout30) resp.raise_for_status() content resp.json()[choices][0][message][content] # 防止模型返回内容中带有 json 代码块标记 content content.strip() if content.startswith(): content content.split(\n, 1)[1] content content.rsplit(, 1)[0] return json.loads(content)这里需要注意几点API_URL、API_KEY、MODEL_NAME需要根据你实际使用的厂商调整。国内很多大模型平台提供 OpenAI 兼容接口只需要修改接口地址和密钥。大模型可能返回 Markdown 代码块格式所以代码中做了简单的清理处理。超时时间设置为 30 秒避免接口异常导致测试永久挂起。该模块属于核心思路演示实际生产环境建议加入重试、缓存、熔断机制。为了不依赖真实的大模型接口也能跑通测试我们实现一个本地兜底策略。当API_KEY为your-api-key或接口调用失败时自动切换到规则定位。# ai_engine.py 追加 DEFAULT_API_KEY your-api-key def fallback_locators(element_desc: str) - list: 本地兜底定位策略根据元素描述返回常见定位器。 text_selector ftext{element_desc} css_selectors [ fbutton:has-text({element_desc}), finput[placeholder*{element_desc}], #username, #password ] result [{type: css, value: css} for css in css_selectors] result.insert(0, {type: text, value: text_selector}) return result def suggest_locators(html_snippet: str, element_desc: str) - list: if API_KEY DEFAULT_API_KEY: return fallback_locators(element_desc) try: # 调用大模型接口 ... except Exception: return fallback_locators(element_desc)这里兜底策略的核心价值是即便断网测试框架仍然能基于文本内容找到按钮。这在工程上非常重要因为 AI 能力应该是“增强”而不是强依赖。4.4 封装页面操作模块pages.py负责封装登录页面操作核心是解决按钮 class 不稳定的问题。# pages.py from playwright.sync_api import Page from ai_engine import suggest_locators class LoginPage: def __init__(self, page: Page): self.page page def get_page_html(self): 获取页面主体 HTML用于发送给大模型分析。 return self.page.content() def click_login_by_text(self): 优先通过文本内容点击登录按钮。 self.page.locator(button:has-text(立即登录)).click() def click_login_with_ai(self, fallback_desc立即登录): 带 AI 辅助的点击登录按钮方案。 html_snippet self.get_page_html() locators suggest_locators(html_snippet, fallback_desc) last_error None for item in locators: try: locator_type item[type] locator_value item[value] if locator_type css: self.page.locator(locator_value).first.click() elif locator_type xpath: self.page.locator(fxpath{locator_value}).first.click() elif locator_type text: self.page.locator(locator_value).first.click() return True except Exception as e: last_error e continue if last_error: raise last_error return False def fill_username(self, username: str): self.page.locator(#username).fill(username) def fill_password(self, password: str): self.page.locator(#password).fill(password)这个封装的思路是先尝试通过文本内容text立即登录定位。文本比 class 稳定得多。如果文本定位失败再调用 AI 接口分析 HTML生成多个候选定位器。按顺序尝试候选定位器直到成功。全部失败则抛出最后一个异常。4.5 非预期弹窗处理模块在真实项目中弹窗是最常见的失败原因。我们在pages.py中增加一个弹窗处理函数# pages.py 追加 POPUP_SELECTORS [ button:has-text(确定), button:has-text(我知道了), button:has-text(取消), .el-message-box__close, [class*close], [aria-labelClose] ] def handle_unexpected_popup(page: Page): 处理非预期弹窗返回是否处理了弹窗。 for selector in POPUP_SELECTORS: try: locator page.locator(selector).first if locator.is_visible(timeout1000): locator.click() return True except Exception: continue return False这个函数放在每次点击页面元素之前调用。由于is_visible(timeout1000)保证了检查时间很短不会明显拖慢测试速度。在实际工程中更完整的做法是维护一个“已知弹窗白名单”。当弹窗出现时先判断是否在名单中。不在名单中的截图记录并标记为“异常现象”。4.6 编写测试用例使用pytest编写测试用例。conftest.py负责管理浏览器生命周期# conftest.py import pytest from playwright.sync_api import sync_playwright pytest.fixture(scopefunction) def page(): with sync_playwright() as p: browser p.chromium.launch(headlessFalse) context browser.new_context() page context.new_page() yield page browser.close()测试用例文件# test_login.py from pages import LoginPage, handle_unexpected_popup BASE_URL http://127.0.0.1:5000 def test_login_with_ai_locator(page): handle_unexpected_popup(page) page.goto(BASE_URL) login_page LoginPage(page) login_page.fill_username(test_user) login_page.fill_password(123456) # 先处理一次可能出现的弹窗 handle_unexpected_popup(page) # AI 辅助点击登录按钮 login_page.click_login_with_ai() # 断言登录成功 page.wait_for_selector(.welcome-user, timeout5000) assert page.locator(.welcome-user).inner_text() test_user运行测试前请先启动被测应用python app.py再开一个终端执行pytest test_login.py -v预期结果test_login_with_ai_locator PASSED由于按钮 class 是随机变化的如果你的脚本通过固定 class 定位多次运行可能偶发失败。而我们的脚本通过文本和大模型辅助定位可以稳定通过。4.7 增加失败自动截图与AI错误分析测试失败时自动保存截图和页面源码是工程中非常实用的能力。# conftest.py 追加 import os from datetime import datetime pytest.hookimpl(tryfirstTrue, hookwrapperTrue) def pytest_runtest_makereport(item, call): outcome yield report outcome.get_result() if report.when call and report.failed: page item.funcargs.get(page) if page: ts datetime.now().strftime(%Y%m%d_%H%M%S) os.makedirs(reports, exist_okTrue) page.screenshot(pathfreports/failure_{ts}.png) with open(freports/failure_{ts}.html, w, encodingutf-8) as f: f.write(page.content())这样每次失败都会在reports目录下留下截图和 HTML 快照。后续可以再写一个 AI 分析函数把截图发送给大模型让模型给出失败原因和修复建议。4.8 AI 分析失败截图示例# ai_engine.py 追加 import base64 def analyze_failure_screenshot(image_path: str) - str: 将失败截图发送给大模型返回原因分析。 with open(image_path, rb) as f: image_b64 base64.b64encode(f.read()).decode(utf-8) prompt ( 这是一个自动化测试失败时的页面截图请分析可能失败的原因 并给出排查顺序。重点关注元素遮挡、加载超时、页面报错、权限异常。 ) payload { model: MODEL_NAME, messages: [ { role: user, content: [ {type: text, text: prompt}, {type: image_url, image_url: {url: fdata:image/png;base64,{image_b64}}} ] } ] } headers { Authorization: fBearer {API_KEY}, Content-Type: application/json } resp requests.post(API_URL, jsonpayload, headersheaders, timeout30) resp.raise_for_status() return resp.json()[choices][0][message][content]如果当前大模型接口不支持图片输入可以退化为只分析 HTML 源码。思路是类似的。5. 常见问题与排查思路5.1 浏览器启动失败现象运行 Playwright 时报错Executable doesnt exist。原因只安装了playwright库没有下载浏览器内核。解决playwright install chromium如果需要使用系统已安装的 Chrome可以在启动时指定可执行文件路径browser p.chromium.launch(executable_pathC:/Program Files/Google/Chrome/Application/chrome.exe)5.2 非预期弹窗导致点击失败现象点击操作报错提示元素被遮挡或不可见。排查步骤打开失败截图查看页面是否有遮挡层。确认弹窗选择器是否在当前维护的列表中。检查弹窗出现的时机是在页面加载前还是点击操作后。解决扩展现有弹窗选择器列表。在关键操作前统一调用handle_unexpected_popup。对于动态生成的弹窗建议结合截图 AI 分析定位关闭按钮。避免反复出现的方法把弹窗处理逻辑统一收敛到一个公共模块业务用例不要各自维护处理逻辑。5.3 大模型接口返回解析失败现象json.loads报错模型返回了额外文本。原因部分模型没有严格遵守“只输出 JSON”的要求。解决在提示词中加强约束。解析前先尝试从内容中提取 JSON 子串。增加兜底逻辑接口解析失败时回退到规则定位。代码中已经演示了fallback_locators的思路建议保留这层兜底。5.4 测试偶发超时现象同一个用例有时通过有时失败。原因页面加载时间不稳定或者元素渲染晚于脚本执行。解决使用 Playwright 的内置等待机制如wait_for_selector。把硬编码的time.sleep全部移除。对点击操作先使用locator.wait_for(statevisible)再执行点击。5.5 接口返回慢导致 AI 定位超时现象脚本卡在 AI 接口调用环节。解决设置超时时间如requests.post(..., timeout30)。增加缓存机制相同 HTML 结构不重复调用。接口失败时自动降级为本地规则。问题现象常见原因解决思路浏览器启动失败缺少内核playwright install chromium弹窗遮挡点击弹窗选择器未覆盖统一弹窗处理模块模型返回无法解析提示词约束不足清理 JSON 兜底规则用例偶发失败等待不足使用显式和隐式等待AI 接口超时模型响应慢设置超时 失败降级6. 最佳实践与工程建议6.1 不要把 AI 作为强依赖AI 接口的稳定性、响应速度、成本都是变量。生产级测试框架中AI 定位应当作为“增强策略”而不是“唯一策略”。正确的做法是优先使用稳定、快速、确定性的定位方式例如 ID。当确定性定位失败时再启用 AI 辅助定位。AI 接口不可用时必须有本地兜底方案。对 AI 调用结果做缓存减少重复请求。6.2 设计语义化的测试对象模型把页面元素抽象成业务对象而不是散落的选择器字符串。例如class LoginPage: username_input #username password_input #password login_button button:has-text(立即登录)这样做的好处是当定位方式改进时只需要修改页面对象类测试用例本身不需要大改。6.3 重视测试数据管理UI 自动化的稳定性不仅取决于代码还取决于测试数据。建议测试账号单独维护不与其他团队共用。账号密码用环境变量或密钥管理服务保存不要硬编码到仓库。涉及数据库更新的测试使用事务回滚或专门测试数据。6.4 集成 CI/CD 时的注意事项在 CI 环境中运行 UI 自动化有几个点需要提前确认CI 机器上是否安装浏览器内核。无头模式headless是否启用。被测环境地址是否可以通过 CI 机器访问。测试报告如何归档失败截图如何下载查看。# 无头模式启动 browser p.chromium.launch(headlessTrue)6.5 测试安全与合规意识在执行自动化测试时要确保你有权对该系统进行测试。尤其是涉及登录、接口调用时注意以下几点使用专门创建的测试账号不要扫描真实用户数据。避免对生产环境执行高风险的批量操作。涉及数据删除或修改时优先在测试环境验证。日志中不要输出用户密码等敏感信息。6.6 测试报告与可观测性自动化测试的价值在于及时暴露问题。因此测试报告应该包含通过、失败、跳过的用例数量。失败截图。页面源码快照。关键操作路径。AI 辅助分析结果如果有。可以接入 Allure 或者自建 HTML 报告模板具体不展开了。7. 后续学习路线与总结通过本文的实战项目你已经掌握了一套“AI 自动化测试”的完整落地思路理解传统 UI 自动化测试的维护痛点。掌握 Playwright Python 的基本用法。实现 AI 辅助元素定位并在接口异常时自动降级。实现非预期弹窗的统一处理。在测试失败时自动截图并利用 AI 分析原因。学习到了生产环境中需要注意的工程化问题。下一步可以从以下几个方向继续深入接口自动化学习 Requests Pytest 的接口测试框架掌握如何用 AI 根据接口文档自动生成测试用例。移动端自动化了解 Appium 和 Airtest将 AI 定位思路应用到移动端元素识别。大模型应用深入学习提示词工程掌握如何设计更精准的 AI 测试提示词。自动化测试框架设计研究如何把 AI 能力封装成可复用、可扩展的测试平台能力。最后分享一个实际项目中的经验AI 不会一夜之间替代测试工程师但会用 AI 的测试工程师会逐步替代不会用 AI 的。这里的“用 AI”不是指让模型生成一段脚本而是真正理解测试框架的运行机制知道在哪个环节用 AI 能降低成本、在哪个环节用 AI 只会引入不确定性和维护成本。把本文的案例跑一遍你会对 AI 在自动化测试中的边界有更直观的判断。如果遇到问题欢迎留言交流。