AI智能元素定位:用Playwright构建自适应UI自动化测试框架
这两年自动化测试的热度一直没降过,但真正做过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 或 macOS |
| Python | 3.10 或更高版本 |
| 浏览器 | Chrome(最新稳定版) |
| 自动化库 | Playwright 1.40+ |
| Web框架 | 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(headless=False) 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> <title>AI自动化测试演示系统</title> </head> <body> <h2>欢迎登录</h2> <form method="post" action="/login"> <label>用户名</label> <input type="text" id="username" name="username" placeholder="请输入用户名" /> <label>密码</label> <input type="password" id="password" name="password" placeholder="请输入密码" /> <button type="submit" class="btn-login-v2">立即登录</button> </form> <script> // 模拟前端动态调整,class会被随机修改 const btnMap = ['btn-login', 'btn-submit', 'btn-login-v2']; const btn = document.querySelector('button[type=submit]'); btn.className = btnMap[Math.floor(Math.random() * btnMap.length)]; </script> </body> </html> """ WELCOME_PAGE = """ <!DOCTYPE html> <html> <head><title>登录成功</title></head> <body> <h2>登录成功,欢迎你!</h2> <p class="welcome-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, username=username) 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 = f"HTML片段:\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": f"Bearer {API_KEY}", "Content-Type": "application/json" } resp = requests.post(API_URL, json=payload, headers=headers, timeout=30) 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 = f"text={element_desc}" css_selectors = [ f"button:has-text('{element_desc}')", f"input[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(f"xpath={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-label='Close']" ] def handle_unexpected_popup(page: Page): """处理非预期弹窗,返回是否处理了弹窗。""" for selector in POPUP_SELECTORS: try: locator = page.locator(selector).first if locator.is_visible(timeout=1000): locator.click() return True except Exception: continue return False这个函数放在每次点击页面元素之前调用。由于is_visible(timeout=1000)保证了检查时间很短,不会明显拖慢测试速度。
在实际工程中,更完整的做法是:
- 维护一个“已知弹窗白名单”。
- 当弹窗出现时先判断是否在名单中。
- 不在名单中的,截图记录,并标记为“异常现象”。
4.6 编写测试用例
使用pytest编写测试用例。conftest.py负责管理浏览器生命周期:
# conftest.py import pytest from playwright.sync_api import sync_playwright @pytest.fixture(scope="function") def page(): with sync_playwright() as p: browser = p.chromium.launch(headless=False) 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", timeout=5000) 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(tryfirst=True, hookwrapper=True) 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_ok=True) page.screenshot(path=f"reports/failure_{ts}.png") with open(f"reports/failure_{ts}.html", "w", encoding="utf-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": f"data:image/png;base64,{image_b64}"}} ] } ] } headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } resp = requests.post(API_URL, json=payload, headers=headers, timeout=30) resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"]如果当前大模型接口不支持图片输入,可以退化为只分析 HTML 源码。思路是类似的。
5. 常见问题与排查思路
5.1 浏览器启动失败
现象:运行 Playwright 时报错Executable doesn't exist。
原因:只安装了playwright库,没有下载浏览器内核。
解决:
playwright install chromium如果需要使用系统已安装的 Chrome,可以在启动时指定可执行文件路径:
browser = p.chromium.launch(executable_path="C:/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(state="visible"),再执行点击。
5.5 接口返回慢导致 AI 定位超时
现象:脚本卡在 AI 接口调用环节。
解决:
- 设置超时时间,如
requests.post(..., timeout=30)。 - 增加缓存机制,相同 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(headless=True)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 在自动化测试中的边界有更直观的判断。如果遇到问题,欢迎留言交流。
