AI自动化测试:用Skill固化Web测试经验,告别不稳定脚本
2026/8/30 18:20:20 网站建设 项目流程

AI 写自动化测试,真正难的从来不是“写代码”,而是让 AI 知道:页面元素该用什么方式定位、等待逻辑怎么写才稳定、断言要对应哪些业务规则、测试报告要输出到什么程度。这些知识靠一长串 Prompt 根本装不下,但可以结构化到一个 Skill 里。

很多测试同学用 AI 助手时会遇到同样的尴尬:生成的脚本第一眼很完整,一运行就崩;让它改一个定位符,它把整个文件重写了;让它补一条用例,逻辑和页面流程完全对不上。问题不是模型能力不够,而是我们没有把“测试这门手艺”的系统知识提供给模型。

这篇文章要解决的,就是怎么把 Web 自动化测试的领域经验封装成一个可复用的 Skill。我会从一个可以直接照抄的工程讲起,覆盖 Skill 的目录结构、完整代码、Markdown 报告模板、运行验证和常见问题排查。读完你能在自己的项目里搭建一套专属的 AI 测试 Skill,并理解它背后真正提升效率的机制。

1. 这篇文章真正要解决的问题

1.1 AI 写自动化测试的常见翻车现场

先看几个真实场景。

场景一:让 AI 写一组登录页测试用例。它很快给出一个 Playwright 脚本,看起来逻辑完整,有页面打开、输入用户名密码、点击登录、断言跳转。但一运行,脚本在第一步就超时了。原因是它生成的是固定的time.sleep(3),页面加载慢一点就崩,快一点又白白等三秒。

场景二:让 AI 定位一个按钮。它给了page.locator("text=提交").click()。结果页面上有两处“提交”,一个在导航栏,一个在表单底部。脚本随机点到了一个不可见元素,测试报错。如果团队里有一个懂测试的人,他会告诉你:优先用get_by_role("button", name="提交"),或者给按钮加上稳定的>python -m venv .venv source .venv/bin/activate # Windows 使用 .venv\Scripts\activate pip install playwright playwright install chromium

这里一定要执行playwright install chromium,它会下载 Playwright 需要的浏览器内核。如果跳过这一步,脚本运行时会直接报“可执行文件不存在”的错误。

3.3 准备一个可测试的本地页面

为了不依赖外网环境,我们生成一个简单的本地页面。创建demo/index.html

<!-- 文件路径:demo/index.html --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>测试页面</title> <style> #app { max-width: 600px; margin: 50px auto; font-family: sans-serif; } .status { color: green; font-weight: bold; } </style> </head> <body> <div id="app"> <h1>欢迎使用 AI 测试 Skill</h1> <p>这是一个用于验证 Web 自动化测试 Skill 的本地页面。</p> <button id="submit-btn">提交</button> <input id="search-input" placeholder="请输入关键词" /> </div> </body> </html>

在项目根目录执行:

python -m http.server 8080

然后浏览器访问http://127.0.0.1:8080/,看到页面说明本地环境正常。

如果不想在本机起服务,也可以用公开测试站点,但要注意不要对没有授权的站点做高频自动化访问。本地页面是最稳定、最安全的选择。

4. 测试 Skill 的目录结构与设计思路

4.1 整体目录结构

一个 Web 自动化测试 Skill 可以这样组织:

web-test-skill/ ├── SKILL.md ├── scripts/ │ ├── run_web_test.py │ └── generate_test_case.py ├── examples/ │ └── smoke_test_demo.md ├── docs/ │ ├── best_practices.md │ └── troubleshooting.md └── requirements.txt

先建目录:

mkdir -p web-test-skill/scripts mkdir -p web-test-skill/examples mkdir -p web-test-skill/docs

4.2 每个文件的作用

  • SKILL.md是 Skill 的入口,AI 会优先读取它。
  • scripts/run_web_test.py是核心执行脚本,负责访问页面、检查元素、生成报告。
  • scripts/generate_test_case.py是辅助脚本,用于批量生成测试用例 Markdown 骨架。
  • examples/存放调用示例,AI 生成新脚本时可以参考。
  • docs/存放最佳实践和排查手册,进一步增强 Skill 的知识量。
  • requirements.txt声明 Python 依赖。

这种拆分的好处是:指令和可执行能力分离。SKILL.md负责告诉 AI“怎么做”,scripts/负责真正执行,docs/负责提供深层知识。AI 在运行 Skill 时,可以根据任务需要调用不同的文件。

4.3 Skill 的加载机制说明

不同 AI 工具对 Skill 的目录约定不完全一样。比较常见的做法是把 Skill 目录放到项目下的.claude/skills/或类似的约定目录中,主文件名固定为SKILL.md

例如:

cp -r web-test-skill .claude/skills/web-test-skill

如果你的工具支持自定义 Skill 加载路径,也可以配置到公共目录,供多个项目复用。具体字段名和加载语法,请以你正在使用的工具文档为准。本文重点是教你把 Skill 的内容搭起来,工具差异不影响核心设计。

5. 完整代码实现

这一节是全文的重点。我会按文件逐个给出完整代码,并解释关键逻辑。你可以直接复制,改一改路径就能用。

5.1 SKILL.md 主文件

SKILL.md是整个 Skill 的核心。AI 面对测试任务时,会通过这个文件了解你的测试规范。

--- name: web-test-skill description: Web 自动化测试实战技能。适用于使用 Playwright 编写和执行 UI 自动化测试、定位页面元素、设计测试断言、生成 Markdown 测试报告的场景。当用户需要做 Web 端功能回归、冒烟测试、页面元素定位或测试用例设计时,优先使用本 Skill。 allowed-tools: - Bash - Read - Write - Edit --- # Web 自动化测试 Skill ## 使用流程 1. 先确认被测页面 URL,能本地访问就优先本地访问,不要直接对没有授权的线上服务发起自动化请求。 2. 编写 Playwright 脚本时,先明确要验证的业务场景,再编写步骤。 3. 每条断言必须有明确的业务含义,失败信息要包含期望值、实际值和定位信息。 4. 测试结束后生成 Markdown 报告,说明总体结论和失败分析。 ## 定位策略优先级 从高到低依次选择: 1. `get_by_test_id` 或 `data-testid` 2. `get_by_role`,如按钮、链接、输入框 3. `get_by_label` / `get_by_placeholder` 4. CSS 选择器 5. XPath,仅在以上方法都不满足时使用 ## 等待与稳定性要求 - 禁止直接使用 `time.sleep(3)` 等待元素,这会降低脚本稳定性。 - 优先使用 `wait_for_selector`、`wait_for_load_state`、`expect` 等显式等待。 - 所有超时时间必须可配置,默认超时为 10 秒。 ## 断言规范 - 断言内容必须对应业务规则,而不是只判断元素存在。 - 失败信息必须包含期望值、实际值和定位信息。 - 不要把多个断言写在同一行。 - 断言失败时,应保留当前页面截图作为排查依据。 ## 报告要求 - 输出格式为 Markdown。 - 报告头部包含测试时间、测试地址、执行环境。 - 每个检查项的状态必须是:通过、失败、阻塞。 - 截图仅作为辅助证据,最终结论以断言结果为准。 ## 脚本调用约定 - 执行冒烟测试时,使用 `python scripts/run_web_test.py`。 - 生成测试用例时,使用 `python scripts/generate_test_case.py`。 - 所有路径均相对于 Skill 根目录。

关键点在于:description要写得足够明确,这样 AI 才能在多种任务中准确识别什么情况下应该加载这个 Skill。allowed-tools声明了 Skill 运行时允许使用的权限范围,按照最小权限原则配置即可。

5.2 自动化测试执行脚本 run_web_test.py

这个脚本完成三件事:访问被测页面、执行检查项、输出 Markdown 报告。

# 文件路径:web-test-skill/scripts/run_web_test.py import argparse import os import sys import time from datetime import datetime from playwright.sync_api import sync_playwright def build_report(url, results, screenshot_path): lines = [ "# Web 自动化测试报告", "", f"- 测试时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", f"- 测试地址:{url}", f"- 截图文件:`{screenshot_path}`", "", "## 检查项结果", "", "| 检查项 | 结果 | 说明 |", "| --- | --- | --- |", ] for item in results: status = "通过" if item["ok"] else "失败" lines.append(f"| {item['name']} | {status} | {item['message']} |") return "\n".join(lines) def main(): parser = argparse.ArgumentParser(description="基于 Playwright 的 Web 自动化测试脚本") parser.add_argument("--url", required=True, help="被测页面 URL") parser.add_argument("--selector", default="body", help="核心元素选择器") parser.add_argument("--expected-title", default="", help="预期页面标题片段") parser.add_argument("--timeout", type=int, default=10000, help="元素等待超时时间,单位毫秒") parser.add_argument("--output-dir", default="reports", help="报告输出目录") parser.add_argument("--headless", action="store_true", help="是否以无头模式运行") args = parser.parse_args() os.makedirs(args.output_dir, exist_ok=True) results = [] with sync_playwright() as p: browser = p.chromium.launch(headless=args.headless) page = browser.new_page() # 检查点 1:页面是否能成功访问 try: response = page.goto(args.url, wait_until="load", timeout=args.timeout) results.append({ "name": "页面访问", "ok": response is not None and response.ok, "message": f"HTTP {response.status}" if response else "无响应", }) except Exception as exc: results.append({"name": "页面访问", "ok": False, "message": str(exc)}) # 检查点 2:页面标题是否符合预期 if args.expected_title: actual_title = page.title() results.append({ "name": "页面标题", "ok": args.expected_title in actual_title, "message": f"期望包含「{args.expected_title}」,实际为「{actual_title}」", }) # 检查点 3:关键元素是否可见 try: page.wait_for_selector(args.selector, timeout=args.timeout) results.append({ "name": "关键元素", "ok": True, "message": f"选择器 {args.selector} 已可见", }) except Exception as exc: results.append({"name": "关键元素", "ok": False, "message": str(exc)}) screenshot_path = os.path.join( args.output_dir, f"screenshot_{int(time.time())}.png" ) page.screenshot(path=screenshot_path) browser.close() report = build_report(args.url, results, screenshot_path) report_path = os.path.join(args.output_dir, "report.md") with open(report_path, "w", encoding="utf-8") as f: f.write(report) print(report) failed = [r for r in results if not r["ok"]] sys.exit(1 if failed else 0) if __name__ == "__main__": main()

脚本的核心逻辑有三个设计值得注意:

第一,检查项被设计成列表,每个检查项都有独立的成功/失败状态。这样即使一个检查项失败,其他检查项也不会被跳过,报告内容会更完整。

第二,所有等待都通过 Playwright 的wait_for_selector(timeout=args.timeout)完成,而不是time.sleep。这是 Web 自动化测试稳定性的关键。

第三,脚本结束时根据是否有失败项返回不同的退出码。这样把脚本接入 CI 流水线时,可以直接用退出码判断测试是否通过。

5.3 测试用例生成辅助脚本 generate_test_case.py

除了执行冒烟测试,Skill 还应该帮助 AI 快速生成结构化的测试用例文档。这个辅助脚本根据传入的步骤 JSON,生成一个 Markdown 用例骨架。

# 文件路径:web-test-skill/scripts/generate_test_case.py import argparse import json from datetime import datetime from pathlib import Path TEMPLATE = """# 测试用例:{case_name} ## 前置条件 - [ ] 被测环境已部署 - [ ] 测试数据已准备 ## 操作步骤 | 步骤 | 操作 | 预期结果 | 实际结果 | 是否通过 | | --- | --- | --- | --- | --- | {steps} ## 自动化脚本要点 ```python # TODO: 根据上述步骤,使用本 Skill 的定位与断言规范编写 # 可参考 examples/ 下的示例。

备注

  • 优先级:{priority}
  • 创建时间:{created_at} """

def main(): parser = argparse.ArgumentParser(description="生成测试用例 Markdown 骨架") parser.add_argument("--name", required=True, help="用例名称") parser.add_argument("--steps", help="步骤 JSON 数组") parser.add_argument("--priority", default="P2", help="优先级 P0/P1/P2") args = parser.parse_args()

steps = [] if args.steps: steps = json.loads(args.steps) step_lines = [] for idx, step in enumerate(steps, 1): op = step.get("操作", "") expected = step.get("预期", "") step_lines.append(f"| {idx} | {op} | {expected} | | |") if not step_lines: step_lines.append("| 1 | 打开被测页面 | 页面正常加载 | | |") content = TEMPLATE.format( case_name=args.name, steps="\n".join(step_lines), priority=args.priority, created_at=datetime.now().strftime("%Y-%m-%d %H:%M:%S"), ) out_path = Path(f"cases/{args.name}.md") out_path.parent.mkdir(exist_ok=True, parents=True) out_path.write_text(content, encoding="utf-8") print(f"用例已生成:{out_path}")

ifname== "main": main()

执行示例: ```bash python scripts/generate_test_case.py \ --name "登录成功用例" \ --steps '[{"操作":"打开登录页","预期":"页面加载完成"},{"操作":"输入正确用户名和密码","预期":"输入成功"},{"操作":"点击登录按钮","预期":"跳转到首页,右上角显示用户名"}]' \ --priority "P0"

这个脚本的意义在于:它把“测试用例应该长什么样”固化了下来。AI 在编写用例时,不再自由发挥格式,而是按照这个骨架输出,团队评审和后续统计都更方便。

5.4 报告模板 report_template.md

为了让 Skill 生成的报告风格统一,再准备一个 Markdown 报告模板:

# {测试项目} 自动化测试报告 - 执行时间:{time} - 执行人:{owner} - 执行环境:{env} ## 汇总 - 用例总数:{total} - 通过数:{passed} - 失败数:{failed} - 通过率:{pass_rate} ## 结果明细 {result_table} ## 失败分析 {failure_analysis} ## 结论 {conclusion}

这个模板可以放在docs/report_template.md里。当 AI 需要生成完整测试报告时,要求它严格按模板填充,保证团队所有报告结构一致。

5.5 依赖声明 requirements.txt

在 Skill 根目录添加依赖文件:

# 文件路径:web-test-skill/requirements.txt playwright>=1.40.0

如果需要用 pytest 体系做更细粒度的用例管理,可以再加:

pytest>=7.0.0 pytest-playwright>=0.4.0

安装命令:

pip install -r requirements.txt

5.6 示例文档 examples/smoke_test_demo.md

为了增强 Skill 的引导能力,可以在examples/下放一个冒烟测试示例,AI 在生成新脚本时可以参考。

# 冒烟测试示例:本地测试页面 ## 目标 验证本地测试页面可以正常打开,标题正确,核心按钮可见。 ## 命令 ```bash python scripts/run_web_test.py \ --url http://127.0.0.1:8080/ \ --selector "#submit-btn" \ --expected-title "测试页面" \ --output-dir reports

预期结果

  • 页面访问检查项:通过
  • 页面标题检查项:通过
  • 关键元素检查项:通过
把示例写进 Skill 目录,相当于给 AI 一本“别人已经跑通的作业”,它生成代码时的模仿成本会低很多。 ## 6. 运行结果与效果验证 ### 6.1 把 Skill 接入项目 先把 Skill 目录复制到 AI 工具的 Skill 加载目录,以常见的 `.claude/skills/` 约定为例: ```bash cp -r web-test-skill .claude/skills/web-test-skill

然后确认目录结构:

find .claude/skills/web-test-skill -maxdepth 2 -type f

正常输出应该包含:

.claude/skills/web-test-skill/SKILL.md .claude/skills/web-test-skill/requirements.txt .claude/skills/web-test-skill/scripts/run_web_test.py .claude/skills/web-test-skill/scripts/generate_test_case.py

6.2 运行冒烟测试

启动本地页面:

python -m http.server 8080

执行 Skill 中的测试脚本:

python .claude/skills/web-test-skill/scripts/run_web_test.py \ --url http://127.0.0.1:8080/ \ --selector "#submit-btn" \ --expected-title "测试页面" \ --output-dir reports \ --headless

预期输出类似:

# Web 自动化测试报告 - 测试时间:2025-01-01 12:00:00 - 测试地址:http://127.0.0.1:8080/ - 截图文件:reports/screenshot_1704000000.png ## 检查项结果 | 检查项 | 结果 | 说明 | | --- | --- | --- | | 页面访问 | 通过 | HTTP 200 | | 页面标题 | 通过 | 期望包含「测试页面」,实际为「测试页面」 | | 关键元素 | 通过 | 选择器 #submit-btn 已可见 |

同时,reports/report.md和截图文件会生成到本地。

6.3 如何判断 Skill 生效

判断 Skill 是否真正被 AI 加载,可以从两个角度验证:

第一,直接运行脚本,确认脚本本身可用。这是最基础的验证。

第二,在 AI 对话中描述一个测试需求,观察它是否引用了 Skill 中的规范。例如你问“用我们的测试规范写一个登录页检查”,如果 AI 自动使用了get_by_rolewait_for_selector,并主动要求生成 Markdown 报告,说明 Skill 已经在起作用。

如果 AI 完全没有反应,大概率是 Skill 目录位置或描述信息没有配置正确。可以检查描述里是否包含了“Web 自动化测试”“Playwright”“测试报告”等触发词。

7. 常见问题与排查思路

实际落地时,会遇到的问题往往不在代码本身,而在环境、工具集成和稳定性上。下面列出高频问题。

问题现象可能原因排查方式解决方案
运行脚本报“Executable doesn't exist”未安装 Playwright 浏览器内核检查 Playwright 安装目录执行playwright install chromium
打开页面超时本地服务端口不对,或 URL 写错浏览器手动访问 URL 确认页面可打开检查--url,确认服务已启动
元素定位不到选择器过期,或在 iframe / shadow DOM 中打开浏览器 DevTools 验证选择器能命中唯一元素改用>期望按钮文案为「提交订单」,实际为「提交」。

而不是:

locator not found

8.5 使用 testid 作为首选定位方式

如果项目还在开发阶段,建议在关键交互元素上统一添加>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询