写了两年代码、带过十几个测试开发任务之后我对“AI for Testing”这件事的态度经历了一次不小的转弯。刚接触AI辅助写自动化脚本时我踩过最深的坑就是让AI凭空生成完整脚本给它一个场景描述它噼里啪啦吐出一大段代码看起来结构完整、注释齐全放到我们项目里却根本合不进去——不是框架调用方式对不上就是等待策略和我们约定不符连类名风格都明显是另一个世界来的。后来我开始琢磨一件事与其逼AI凭空猜我们的技术债和工程约定不如把现有框架本身变成它的工作环境让它在我们已经跑得起来的框架里写脚本。这篇文章就是这套思路的完整实操记录核心一句话别让AI凭空写脚本让它在你的框架里写产出才能直接合入。1. 整体设计思路把AI当作“懂规矩的新成员”而不是“代码生成器”1.1 凭空写脚本为什么总是“看起来能用合入就废”先说痛点。让AI直接根据一句“帮我写个登录用例”生成脚本大多数时候你会得到一段“demo级”代码类结构漂亮、注释齐全、断言也写了但放到真实仓库里问题立刻爆炸。我总结下来主要有三类致命伤。第一没有验收基线的代码无法判断好坏。AI不知道你们的测试代码需要满足什么标准它只能基于通用最佳实践自由发挥。而一个真实项目的测试代码是有静态检查、代码规范、目录约定、执行超时、失败重试、报告接入等一堆隐性地基要求的。这些要求散落在仓库的各个配置文件和既有用例里你不主动约束AI永远不会知道。第二脱离被测系统的代码充满“猜测”。AI生成的元素定位经常基于它想象中的前端结构比如自己编一个idusername或者写driver.find_element(By.XPATH, //input[placeholder请输入用户名])。这类定位在你没给它真实页面结构信息时约等于掷骰子。就算碰巧对上了也会因为选择器过于脆弱下一次前端小改动就挂掉。第三风格不统一导致Review成本巨高。团队里既有case的路由方式、数据准备手段、失败截图逻辑、日志写法都是长期磨合出来的共识。AI生成的代码哪怕功能正确只要风格不一致Reviewer就得一行行解释“为什么这里要用 fixture 而不是直接初始化”“为什么元素定位要抽到 locator 文件里”。这种沟通成本抵消了AI带来的提效最后你宁愿自己写。注意让AI在框架里写脚本本质上不是“降低AI能力”而是把团队已经沉淀的工程约束变成可被AI读取的上下文。框架就是你的验收基线AI每产出一段代码都要被这套基线过滤一遍。1.2 核心思路让框架变成AI的工作环境解决上面三个痛点的思路其实很朴素如果你给AI的输入里包含了你们框架的目录结构、公共方法、元素定位约定、等待策略、命名规范、异常处理约定那么AI的输出就会被这些约束“套住”产出自然向团队标准靠拢。我把这个思路称为**“框架契约驱动”**。所谓框架契约就是一份机器可读、逻辑清晰、能被AI理解和遵守的“工程说明文档”。它不玄乎就是把一个测试框架的“交通规则”总结出来哪些可以调用、哪些必须禁止、代码该放在哪、命名用什么风格、断言怎么写、数据怎么准备。把这份契约在会话一开始就投喂给AI它写出来的东西就不再是广场上的即兴表演而是带着镣铐跳舞——只不过这副镣铐恰好是你们团队最舒服的规范。这样做还有一个附加好处契约文档本身会倒逼团队反思框架现状。我在整理契约的过程中就发现我们有个公共方法居然有七八个形似的命名变体还有一套老接口没有封装、导致每个用例都在裸写HTTP调用。为了给AI一份清晰契约这些历史债被提前暴露了出来。1.3 这套做法适合什么场景如果你所在的团队测试代码量已经有一定规模有明确的框架选型比如 Python Pytest Selenium、Java TestNG Selenium 等且你希望AI产出的脚本能直接进入CI流程那么这套“框架契约驱动”的方法就是为你的场景设计的。反过来如果团队本来就没有沉淀框架、每个用例都是一把梭的脚本文件那么建议先花一两个迭代把公共能力抽出来再做AI提效。否则AI在一个混乱的环境里写代码大概率会继承并放大混乱。我见过有同学在没有目录约束的情况下让AI生成200个用例文件结果全是复制粘贴的重复代码那个场面比手动写还难收拾。2. 动手准备如何构造一份能被AI高效消化的“框架契约”2.1 框架契约要包含哪些核心模块框架契约不是把整个项目源码丢给AI那样信息量太大AI反而抓不住重点。你需要的是经过提炼的“使用说明书”。我实践下来按下面六块来整理最有效。第一块目录结构与新增文件位置。告诉AI用例该放在哪个目录、页面对象放哪里、数据文件放哪里、公共方法从哪个包导入。比如项目结构 - pages/ # 页面对象模型POM - testcases/ # 测试用例按模块分子目录 - data/ # 测试数据文件JSON/YAML - common/ # 公共方法封装 - conftest.py # pytest fixture第二块公共方法清单与签名。把框架里最常用的公共方法整理成表格包括方法名、参数、返回值、用途、示例。这是AI最容易“凭空发明”的部分也是最需要约束的部分。比如“登录”不应该让AI自己拼driver.find_element...而应该让它调用现成的common.login(username, password)。第三块元素定位与选择器规范。明确告诉AI哪些定位方式优先、哪些禁止。我们团队约定是优先 id、其次>你是一名资深测试开发工程师正在为团队现有的自动化测试框架补充用例。 请严格遵守以下框架契约所有代码必须与既有代码风格保持一致 [把框架契约粘贴到这里]第二段给出明确的任务描述包括被测功能点、验收标准、涉及的数据。请为以下功能编写自动化测试用例 功能用户登录包含成功登录、密码错误、账号锁定 验收标准 - 成功登录后跳转到首页右上角显示用户名 - 密码错误提示“用户名或密码错误” - 密码连续错误5次后账号锁定 被测环境测试环境地址 http://test.example.com第三段明确产出物格式。请产出以下内容 1. 页面对象类代码如需新建需遵循POM规范 2. 测试用例代码 3. 需要用到的测试数据以JSON格式给出 4. 简要说明每个用例覆盖的边界场景第四段设定Review要求。让AI在生成代码前先自查一遍。在输出前请逐条对照框架契约检查 - 是否使用了契约禁止的定位方式 - 是否直接使用了 time.sleep - 是否引入了契约中没有的方法 - 是否存在硬编码数据 如果不符合自行修改后再输出。这套四段式模板我连续用了三个月最大的感受是产出稳定性明显提升。尤其是第四段自查能把一多半的“习惯性坏味道”在输出前就过滤掉。2.3 上下文管理的两个细节第一每次会话只做一件事。很多同学喜欢在一个会话里连续让AI写多个用例结果AI的“记忆”越来越淡后面的产出开始偏离契约。我强烈建议一个会话聚焦一个功能模块写完一个就关闭会话、重新开启新会话并重新投喂契约。虽然看起来重复投喂很啰嗦但产出质量是线性提升的。第二把契约存成独立文件。框架契约不要每次从聊天记录里翻找直接放进项目仓库比如docs/ai_framework_contract.md每次复制粘贴很方便还能让团队其他成员维护这个文件。契约文件本身就是一项团队资产。3. 核心实操让AI在既有UI框架里产出可直接合入的脚本3.1 模拟场景设定为了让步骤清楚我构造一个演示场景。假设团队框架是 Python Pytest Selenium被测对象是一个“某后台管理系统”本次需求是补充“用户管理”模块的用例列表加载、按状态筛选、进入用户详情页。框架现状如下# common/base.py class BasePage: def __init__(self, driver): self.driver driver def wait_element(self, by, value, timeout10): # 封装了显式等待禁止用例直接使用 WebDriverWait ... # common/login.py def login(driver, username, password): # 已封装登录流程用例中禁止再写登录步骤 ... # pages/user_page.py class UserPage(BasePage): # 现有方法open_user_list(), get_user_row_count(), get_status_filter_options() ...我给出契约片段浓缩版约定 1. 用例统一继承 common.base.BaseCase所有用例使用driver fixture 2. 登录统一调用 common.login.login() 3. 元素定位统一放在pages/user_page.py中用例层禁止出现find_element 4. 等待用BasePage.wait_element()禁止time.sleep 5. 断言使用pytest.assume或assert不引入新断言库 6. 命名用例方法 test_开头页面方法小驼峰3.2 第一轮先让AI产出页面对象方法按照实操流程我不会让AI一上来就写测试用例而是先让它补齐页面对象层。这个顺序非常关键页面对象是对前端页面的抽象AI如果没看过真实页面结构就需要你把关键定位信息给它。我给AI的输入除了契约还额外附上了从浏览器DevTools里摘出来的真实定位信息需要补充的页面元素来自当前线上环境 - 用户列表表格iduser-table - 状态筛选下拉框idstatus-filter - 筛选确认按钮idfilter-submit - 行内“详情”链接classuser-detail-link - 详情页标题classdetail-titleAI产出的页面对象补充如下演示class UserPage(BasePage): def filter_by_status(self, status_value): self.wait_element(By.ID, status-filter) filter_select self.driver.find_element(By.ID, status-filter) Select(filter_select).select_by_value(status_value) self.driver.find_element(By.ID, filter-submit).click() self.wait_element(By.ID, user-table) def get_user_names(self): rows self.wait_elements(By.CSS_SELECTOR, #user-table tbody tr) return [row.find_element(By.CLASS_NAME, user-name).text for row in rows] def open_user_detail(self, row_index0): # 打开第一行用户的详情 user_row self.driver.find_elements(By.CSS_SELECTOR, #user-table tbody tr)[row_index] user_row.find_element(By.CLASS_NAME, user-detail-link).click() self.wait_element(By.CLASS_NAME, detail-title)这段代码仍然有使用By.XPATH吗没有。有time.sleep吗没有。它调用了契约里的wait_element定位信息来自真实页面方法职责清晰可以直接放进pages/user_page.py。关键心得给AI真实定位信息这一步不能省。AI再怎么聪明也无法“看见”你代码仓库背后的页面结构。你在DevTools里花两分钟复制的几个选择器直接决定了AI产出能否在真实环境跑通。3.3 第二轮让AI基于页面对象生成用例脚本页面对象层确认没问题后再让AI写用例层。这个时候AI的上下文里已经包含了框架契约 页面对象定义它不需要再凭空设计操作步骤只需要按业务场景组合页面方法。请基于以下页面对象方法编写3条测试用例 1. 用户列表默认加载断言表格行数大于0 2. 按状态“启用”筛选断言返回的用户中不存在“禁用”状态 3. 打开第一个用户的详情页断言详情页标题包含用户名AI产出演示def test_user_list_loads_successfully(driver): login(driver, admin, 123456) user_page UserPage(driver) user_page.open_user_list() assert user_page.get_user_row_count() 0 def test_filter_by_status_enabled(driver): login(driver, admin, 123456) user_page UserPage(driver) user_page.open_user_list() user_page.filter_by_status(enabled) user_names user_page.get_user_names() # 从接口返回校验状态字段或从表格中读取状态列 assert user_page.get_status_texts() [启用] * len(user_names) def test_open_detail_shows_username(driver): login(driver, admin, 123456) user_page UserPage(driver) user_page.open_user_list() first_user_name user_page.get_user_names()[0] user_page.open_user_detail(0) assert first_user_name in user_page.get_detail_title()三条用例全部基于已封装方法没有裸用find_element没有硬编码等待业务意图清晰。这种产出放到Code Review里Reviewer只需要关注业务覆盖是否充分而不用去纠正任何框架用法问题。3.4 合入门禁让“能合入”不只靠感觉在我个人实践里“能不能直接合入”需要被机器验证而不是靠人工看一眼代码风格就放行。建议在MR/PR流水线里加几道硬性门禁。第一道静态检查与风格校验运行 ruff/flake8 或对应的 Java 栈 checkstyle保证代码风格统一。AI即使偶尔在自由发挥也会被静态检查揪出来重新生成。第二道命令规范校验写一个简单的 shell 或 pre-commit 钩子grep 新增代码里是否出现time.sleep、find_element(By.XPATH等黑名单关键字一旦出现直接打回。第三道最低覆盖校验新增用例必须能映射到已有冒烟集跑一遍核心链路确认不破坏现有功能。第四道人工评审聚焦在“业务场景”层面既然AI已经把框架规范问题都排掉了Reviewer的精力就可以真正花在“这条用例是否覆盖了需求边界”上这是最有价值的评审。提示这套门禁加上后虽然前期初始化多花了两小时但后面每一次AI生成脚本的合入时间从“沟通加返工两轮”缩短到“评审十分钟”。这个投入绝对划算。4. 常见问题与排查技巧实录在这套“框架契约驱动”流程跑了几个月之后我积累了一些高频问题的排查经验整理成速查表。问题现象根本原因排查思路解决方案AI生成的代码里出现框架里不存在的方法契约中公共方法清单不全或AI没被严格要求“只调用契约列出的方法”搜索代码中是否存在未在pages/common中出现的方法名在契约中增加“禁止调用以下不存在的方法”清单并在自查段明确要求元素定位频繁使用脆弱的XPath文本定位契约中未明确禁止的定位方式AI按通用套路输出检查新增代码里的By.XPATH和包含中文文本的选择器在契约中加粗定位优先级id >
阅读完成 · 觉得有帮助?