你有没有算过:写一个完整的Selenium登录测试脚本,从定位元素到加断言,要花多长时间?30分钟?1小时?

再算算Appium——光配desired_caps、处理混合App的context切换、调试XPath定位,半天就过去了。

如果有个工具,你用一句话描述测试意图,它就能生成可运行的POM框架代码——你会不会心动?

这篇文章带你用Cursor + Selenium/Appium搭建一套AI驱动的自动化测试工作流。不是概念灌水,是可复制的实操流程,每段代码都能跑。


一、为什么是 Cursor?AI 时代测试工程师的新生产力工具

1.1 Cursor是什么

Cursor是一款基于VS Code深度定制的AI原生IDE,内置Claude 3.5 Sonnet和GPT-4o等模型。它不是在编辑器里加了个聊天窗口,而是从底层重新设计了AI与代码的交互方式

对测试工程师来说,这意味着什么?你不需要从零手写每一行定位代码、每一个等待逻辑、每一条断言——你用自然语言描述测试意图,Cursor帮你生成可运行的代码

1.2 三大核心能力

能力
做什么
测试场景
Tab 补全
实时预测下一行代码,延迟<200ms
写定位语句时自动补全By策略、Assert断言
Composer
理解多文件上下文,跨文件生成代码
一句话生成BasePage+PageObject+TestCases三层结构
Agent 模式
自主执行多步骤任务,按需调用工具
分析失败用例→定位元素失效→修复脚本→重跑验证

1.3 与Copilot/Claude的区别

维度
Cursor
GitHub Copilot
Claude Web
代码补全
Tab补全+行内
Tab补全+行内
不支持
多文件生成
Composer跨文件
不支持
不支持
项目级理解
索引整个项目
当前文件+少量上下文
仅对话上下文
Agent自主执行
支持
有限支持
不支持
Rules约束
.cursorrules项目级
.github/copilot
无
定价
$20/月Pro版
$10/月
$20/月

💡 一句话总结:Copilot是”你写代码它补全”,Cursor是”你说意图它生成”。对于测试脚本的批量生成,Cursor的Composer模式是当前效率天花板

1.4 它不替代什么

说清楚边界Cursor不替代:

Cursor是放大器,放大你的测试设计能力,不是替代你的思考


二、环境准备:5分钟搭好工作流

2.1 Cursor安装与配置

  1. 访问 cursor.com 下载安装(支持Windows/macOS/Linux)
  2. 打开Cursor → Settings → Models → 选择Claude 3.5 Sonnet(代码生成质量好)
  3. Settings → General → 开启”Auto Save”(Composer生成代码后自动保存)

2.2 Selenium环境(Python)

# 创建虚拟环境python -m venv venvsource venv/bin/activate  # Windows: venv\Scripts\activate# 安装依赖pip install selenium pytest webdriver-manager pytest-html# 验证python -c "from selenium import webdriver; print('Selenium OK')"pytest --version

2.3 Appium环境

Appium环境比Selenium复杂,分Android和iOS两部分:

Android必需

iOS必需(macOS)


三、Cursor + Selenium:Web自动化脚本生成实战

3.1 场景:电商网站登录+搜索+加购物车

我们用一个真实场景演示:测试某电商网站的”用户登录→搜索商品→加入购物车”流程

3.2 传统做法 vs Cursor做法

步骤
传统做法耗时
Cursor做法耗时
搭POM框架结构
40分钟(手动建目录/文件)
30秒(Composer一次生成)
编写登录页Page Object
20分钟(定位+封装)
2分钟(描述意图,Review生成代码)
编写测试用例
25分钟(组装+断言)
3分钟(描述流程,微调)
加显式等待和异常处理
15分钟(容易遗漏)
1分钟(在Prompt中要求)
合计 ~100分钟 ~7分钟

💡 效率提升约14倍。但注意:生成后必须人工Review,重点检查定位策略的稳定性和断言的完整性

3.3 用Composer一步生成POM框架

在Cursor中按Cmd/Ctrl+I打开Composer,输入以下Prompt:

👤 Prompt示例

在当前项目下生成一个Selenium Web自动化测试框架,使用Python + pytest,POM设计模式。需求:

1. BasePage类:封装find_element、click、input、wait_for_element、take_screenshot公共方法,统一用WebDriverWait显式等待

2. Pages目录:LoginPage(登录页)、SearchPage(搜索页)、CartPage(购物车页)

3. Tests目录:test_login_search_cart.py,测试流程:登录→搜索”手机”→点击第一个商品→加入购物车→验证购物车数量

4. 定位策略优先级:id > name > css > xpath

5. 每个Page类包含__init__接收driver

6. conftest.py提供driver fixture,用webdriver-manager自动管理ChromeDriver

7. 生成pytest.ini配置文件

Cursor会自动创建完整的项目结构:

project/├── pages/│   ├── __init__.py│   ├── base_page.py       # BasePage公共方法│   ├── login_page.py      # 登录页Page Object│   ├── search_page.py     # 搜索页Page Object│   └── cart_page.py       # 购物车页Page Object├── tests/│   ├── __init__.py│   ├── conftest.py        # pytest fixtures│   └── test_login_search_cart.py  # 测试用例├── utils/│   └── __init__.py├── pytest.ini└── requirements.txt

3.4 生成的代码示例:BasePage

from selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import Byimport osclass BasePage:    """所有Page Object的基类,封装公共操作"""    def __init__(self, driver):        self.driver = driver        self.wait = WebDriverWait(driver, 10)    def find_element(self, *locator):        return self.wait.until(            EC.presence_of_element_located(locator)        )    def find_clickable(self, *locator):        return self.wait.until(            EC.element_to_be_clickable(locator)        )    def click(self, *locator):        self.find_clickable(*locator).click()    def input_text(self, text, *locator):        element = self.find_element(*locator)        element.clear()        element.send_keys(text)    def get_text(self, *locator):        return self.find_element(*locator).text    def take_screenshot(self, name="screenshot"):        path = os.path.join("screenshots", f"{name}.png")        os.makedirs("screenshots", exist_ok=True)        self.driver.save_screenshot(path)

3.5 生成的代码示例:LoginPage

from selenium.webdriver.common.by import Byfrom pages.base_page import BasePageclass LoginPage(BasePage):    """登录页Page Object"""    # 定位策略:id优先,css其次,xpath兜底    USERNAME_INPUT = (By.ID, "username")    PASSWORD_INPUT = (By.ID, "password")    LOGIN_BUTTON = (By.CSS_SELECTOR, "button[type='submit']")    ERROR_MESSAGE = (By.CLASS_NAME, "error-msg")    def login(self, username, password):        """执行登录操作"""        self.input_text(username, *self.USERNAME_INPUT)        self.input_text(password, *self.PASSWORD_INPUT)        self.click(*self.LOGIN_BUTTON)    def get_error_message(self):        """获取错误提示信息"""        return self.get_text(*self.ERROR_MESSAGE)    def is_loaded(self):        """验证页面是否加载完成"""        return self.find_element(*self.USERNAME_INPUT).is_displayed()

3.6 生成的代码示例:测试用例

import pytestfrom pages.login_page import LoginPagefrom pages.search_page import SearchPagefrom pages.cart_page import CartPagedef test_login_search_add_cart(driver):    """测试流程:登录→搜索手机→加购物车→验证"""    # Step 1: 登录    login_page = LoginPage(driver)    login_page.login("testuser", "testpass123")    assert login_page.is_loaded() is False  # 登录成功应跳转    # Step 2: 搜索    search_page = SearchPage(driver)    search_page.search("手机")    assert search_page.get_result_count() > 0    # Step 3: 加购物车    search_page.click_first_product()    cart_page = CartPage(driver)    cart_page.add_to_cart()    cart_count = cart_page.get_cart_count()    assert cart_count >= 1, f"购物车数量异常: {cart_count}"
微信公众号二维码图片引自微信公众号,扫码关注阅读原文

Cursor Composer一键生成POM框架过程线稿

3.7 关键Prompt技巧

生成代码的质量,取决于你描述的精度。三个原则:

🎯 核心原则:Prompt越具体,生成代码越可用。模糊的”写个登录测试”只会给你线性脚本+time.sleep,精确的描述才能生成工程级代码。



四、Cursor + Appium:移动端自动化脚本生成实战(Android + iOS)

Appium的复杂度比Selenium高一个量级:平台差异(Android vs iOS)、混合App的context切换、原生组件定位策略不同、手势操作复杂。但Cursor同样能大幅提效

4.1 场景:测试某App的启动→登录→浏览→退出流程

我们分Android和iOS两个平台演示

4.2 Android端:生成Appium测试脚本

👤 Prompt示例(Android)

生成一个Appium Android测试脚本,Python + pytest,测试流程:启动App→登录→浏览首页→退出登录。

要求:

1. 登录:用Accessibility ID定位用户名/密码输入框,输入后点击登录按钮

2. 浏览:滑动首页3次,点击第2个商品进入详情页

3. 退出:返回首页→打开侧边栏→点击退出登录→确认退出

4. 每步加WebDriverWait显式等待,超时10秒

5. 滑动用TouchAction的press+move_to+release实现

6. 用pytest标记@pytest.mark.android

Cursor生成的核心代码:

import pytestfrom appium import webdriverfrom appium.webdriver.common.appiumby import AppiumByfrom appium.webdriver.common.touch_action import TouchActionfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as EC@pytest.mark.androidclass TestAndroidLoginBrowse:    @pytest.fixture(scope="class")    def driver(self):        desired_caps = {            "platformName": "Android",            "automationName": "UiAutomator2",            "appPackage": "com.example.app",  # 替换为实际包名            "appActivity": ".MainActivity",     # 替换为实际Activity            "noReset": True,            "newCommandTimeout": 300,        }        driver = webdriver.Remote("http://127.0.0.1:4723", desired_caps)        yield driver        driver.quit()    def test_login_browse_logout(self, driver):        wait = WebDriverWait(driver, 10)        # Step 1: 登录        username = wait.until(EC.presence_of_element_located(            (AppiumBy.ACCESSIBILITY, "username_input")        ))        username.send_keys("testuser")        password = driver.find_element(            AppiumBy.ACCESSIBILITY, "password_input"        )        password.send_keys("testpass123")        driver.find_element(            AppiumBy.ACCESSIBILITY, "login_button"        ).click()        # Step 2: 验证登录成功(首页元素出现)        home_tab = wait.until(EC.presence_of_element_located(            (AppiumBy.ACCESSIBILITY, "home_tab")        ))        assert home_tab.is_displayed(), "登录后未进入首页"        # Step 3: 滑动浏览首页3次        action = TouchAction(driver)        size = driver.get_window_size()        for i in range(3):            action.press(x=size["width"]//2, y=size["height"]//4) \                 .move_to(x=size["width"]//2, y=size["height"]*3//4) \                 .release().perform()        # Step 4: 点击第2个商品        product = wait.until(EC.presence_of_element_located(            (AppiumBy.XPATH, "(//android.widget.ImageView)[2]")        ))        product.click()        # Step 5: 返回首页→打开侧边栏→退出登录        driver.back()        driver.find_element(            AppiumBy.ACCESSIBILITY, "menu_button"        ).click()        logout_btn = wait.until(EC.presence_of_element_located(            (AppiumBy.ACCESSIBILITY, "logout_button")        ))        logout_btn.click()        # 确认退出        confirm = wait.until(EC.presence_of_element_located(            (AppiumBy.ID, "android:id/button1")        ))        confirm.click()        # 验证回到登录页        login_screen = wait.until(EC.presence_of_element_located(            (AppiumBy.ACCESSIBILITY, "username_input")        ))        assert login_screen.is_displayed(), "退出后未回到登录页"

4.3 iOS端:生成Appium测试脚本

iOS与Android的脚本结构相似,但有几个关键差异需要注意。在Cursor中生成iOS脚本时,要在Prompt中明确指出:

👤 Prompt示例(iOS)

生成一个Appium iOS测试脚本,Python + pytest,测试流程同Android版(启动→登录→浏览→退出)
iOS特殊要求:

1. 定位策略优先用Accessibility ID(iOS的accessibility identifier对应XCUIElement的label)

2. iOS的alert弹窗用driver.switch_to.alert处理,不用ACCESSIBILITY定位

3. 滑动用ActionChains(iOS的TouchAction用法与Android不同)

4. App路径用.app文件(模拟器)

5. 用pytest标记@pytest.mark.ios

6. 增加context切换处理(如果是混合App,需切换到WEBVIEW)

Cursor生成的iOS核心代码:

@pytest.mark.iosclass TestIOSLoginBrowse:    @pytest.fixture(scope="class")    def driver(self):        desired_caps = {            "platformName": "iOS",            "automationName": "XCUITest",            "platformVersion": "17.0",            "deviceName": "iPhone 15",            "app": "/path/to/MyApp.app",  # 替换为实际app路径            "noReset": True,            "newCommandTimeout": 300,        }        driver = webdriver.Remote("http://127.0.0.1:4723", desired_caps)        yield driver        driver.quit()    def test_login_browse_logout(self, driver):        wait = WebDriverWait(driver, 10)        # Step 1: 登录        username = wait.until(EC.presence_of_element_located(            (AppiumBy.ACCESSIBILITY, "username_input")        ))        username.send_keys("testuser")        password = driver.find_element(            AppiumBy.ACCESSIBILITY, "password_input"        )        password.send_keys("testpass123")        driver.find_element(            AppiumBy.ACCESSIBILITY, "login_button"        ).click()        # Step 2: 处理可能的iOS原生alert弹窗        try:            alert = driver.switch_to.alert            alert.accept()        except:            pass  # 无弹窗则继续        # Step 3: 验证登录成功        home_tab = wait.until(EC.presence_of_element_located(            (AppiumBy.ACCESSIBILITY, "home_tab")        ))        assert home_tab.is_displayed()        # Step 4: iOS滑动(用ActionChains)        from selenium.webdriver.common.action_chains import ActionChains        size = driver.get_window_size()        for i in range(3):            ActionChains(driver) \                .move_by_offset(size["width"]//2, size["height"]//4) \                .click_and_hold() \                .move_by_offset(0, size["height"]//2) \                .release() \                .perform()            ActionChains(driver).reset_actions()        # Step 5: 点击第2个商品        product = wait.until(EC.presence_of_element_located(            (AppiumBy.XPATH, "(//XCUIElementTypeImage)[2]")        ))        product.click()        # Step 6: 混合App context切换(如果需要)        if "WEBVIEW" in driver.contexts:            driver.switch_to.context("WEBVIEW")            # 在WebView中操作...            driver.switch_to.context("NATIVE_APP")  # 切回原生        # Step 7: 退出登录        driver.find_element(            AppiumBy.ACCESSIBILITY, "menu_button"        ).click()        logout_btn = wait.until(EC.presence_of_element_located(            (AppiumBy.ACCESSIBILITY, "logout_button")        ))        logout_btn.click()        confirm = wait.until(EC.presence_of_element_located(            (AppiumBy.ACCESSIBILITY, "确认退出")        ))        confirm.click()        # 验证回到登录页        login_screen = wait.until(EC.presence_of_element_located(            (AppiumBy.ACCESSIBILITY, "username_input")        ))        assert login_screen.is_displayed(), "退出后未回到登录页"

4.4 Android vs iOS关键差异对照

维度
Android
iOS
automationName
UiAutomator2
XCUITest
App文件
.apk
.app(模拟器)/ .ipa(真机)
元素类型
android.widget.*
XCUIElementType*
滑动实现
TouchAction(press→move_to→release)
ActionChains(click_and_hold→move_by_offset→release)
alert处理
driver.switch_to.alert 或 ACCESSIBILITY定位
driver.switch_to.alert.accept()
context切换
同iOS(WEBVIEW/NATIVE_APP)
同Android
定位优先策略
Accessibility ID > id > xpath
Accessibility ID(label)> predicate > xpath

💡 Cursor使用技巧:生成跨平台脚本时,在Prompt中明确列出Android和iOS的差异点。Cursor会分别生成两套代码,而不是混在一起。如果你只说”写个Appium测试”,它默认生成Android版——iOS的差异容易遗漏

4.5 跨平台测试框架

更高级的玩法:用Cursor生成一套支持双平台的测试基类,通过pytest marker切换平台:

👤 Prompt示例(跨平台)

生成一个跨平台Appium测试基类CrossPlatformBasePage,支持Android和iOS双平台
要求:

1. 通过pytest marker切换platform,desired_caps在conftest.py中根据marker动态生成

2. 封装公共操作(click, input, swipe, wait)的平台适配层

3. 滑动方法:Android用TouchAction,iOS用ActionChains

4. 提供platform变量,Page Object中可用条件判断处理平台差异

5. 生成conftest.py的driver fixture,根据–platform参数选择Android或iOS的desired_caps

微信公众号二维码图片引自微信公众号,扫码关注阅读原文

Cursor + Appium跨平台工作流线稿:一套Prompt生成双平台脚本



五、Cursor Rules 配置:打造专属测试脚手架

5.1 .cursorrules文件是什么

这是Cursor的项目级AI行为约束文件。放在项目根目录,Cursor在生成代码时会自动遵守其中的规则。相当于给你的AI助手定一份”工作手册”

5.2 推荐的测试领域Rules配置

在项目根目录创建.cursorrules文件:

# 项目:自动化测试框架# 语言:Python 3.10+# 框架:pytest + Selenium/Appium## 代码结构规则- 使用POM(Page Object Model)设计模式- BasePage封装公共操作,所有Page类继承BasePage- 测试用例文件放在tests/目录,Page Object放在pages/目录- 每个Page类只负责一个页面的元素和操作## 定位策略优先级- Web:id > name > css_selector > xpath- Android:accessibility_id > id > xpath- iOS:accessibility_id > predicate_string > xpath- 禁止使用绝对xpath(如/html/body/div[3]/...)## 等待策略- 统一使用WebDriverWait + expected_conditions- 显式等待超时时间:10秒(可通过参数覆盖)- 禁止使用time.sleep()- 页面加载等待用dom_to_be_loaded## 断言规则- 使用pytest原⽣assert,不引入unittest.AssertionError- 每个测试步骤至少一个断言- 断言失败信息包含:期望值、实际值、上下文## 命名规范- Page类:大驼峰+Page后缀,如LoginPage- 测试函数:test_小驼峰+场景描述,如test_login_with_valid_credentials- 定位变量:全大写+下划线,如USERNAME_INPUT

5.3 配置Cursor Skill:一行指令生成用例

Cursor的Skill功能可以让你把重复的Prompt固化为模板。在Cursor中打开Settings → Rules, Skills, Subagents → 新建Skill:

👤 Skill创建Prompt

新增规则:根据需求文档,生成功能测试用例,需要覆盖正向、逆向、异常、并发场景。输出为Python pytest测试函数,包含步骤注释和断言。将用例文件放在tests/目录下

Cursor会创建一个SKILL.md文件。以后只需要在对话中输入/generate-test-cases + 需求描述,就能自动生成符合你项目规范的测试用例

5.4 Rules维护建议


六、进阶玩法:Cursor Agent 模式跑测试流水线

6.1 Agent模式是什么

Cursor 0.43版本引入了Agent模式。与Composer不同,Agent可以自主执行多步骤任务——不只是生成代码,还能运行测试、读取日志、分析失败、修复脚本

6.2 场景:Agent修复一个元素定位失效的用例

假设你的Selenium测试用例跑红了,报错NoSuchElementException——页面改版,登录按钮的id变了

👤 Agent Prompt

运行 tests/test_login_search_cart.py,分析失败的用例。如果失败原因是元素定位失效,检查当前页面的HTML结构,更新定位策略后重新运行验证

Agent会自动执行以下步骤:

  1. 运行pytest tests/test_login_search_cart.py,捕获失败输出
  2. 分析错误:NoSuchElementException: By.ID, "login-btn"
  3. 打开浏览器访问目标页面,分析当前HTML结构
  4. 发现登录按钮改成了<button class="btn-primary" data-testid="login">
  5. 更新定位策略:By.ID → By.CSS_SELECTOR, "[data-testid='login']"
  6. 修改login_page.py中的LOGIN_BUTTON定位
  7. 重新运行测试,验证通过
微信公众号二维码图片引自微信公众号,扫码关注阅读原文

Cursor Agent自动修复失败用例流程线稿

6.3 效率对比

任务
手动修复
Agent修复
运行测试发现问题
5分钟
30秒
排查定位失效原因
10-20分钟
1分钟(自动分析HTML)
修改定位策略
5分钟
10秒
重跑验证
5分钟
30秒
合计 25-35分钟 ~2分钟

💡 Agent模式目前适合定位失效、等待超时、断言值微调这类问题。复杂的业务逻辑Bug仍需人工分析



七、效率对比与避坑指南

7.1 整体效率数据

任务
纯手写
Cursor辅助
提升倍数
搭建POM框架
40分钟
30秒
~80x
编写单页Page Object
20分钟
2分钟
~10x
编写测试用例
25分钟
3分钟
~8x
修复定位失效
30分钟
2分钟
~15x
生成跨平台Appium脚本
90分钟
5分钟
~18x

注意:以上数据基于”5年测试经验工程师 + Cursor Pro”的实测结果。新手效率提升更大,但Review时间也要相应增加

7.2 三个常见坑

坑1:生成的定位策略不够稳定

Cursor生成的代码可能大量使用XPath或CSS选择器,这些定位方式在页面改版时容易失效

解决:在.cursorrules中强制定位优先级(id > accessibility > css > xpath),并在Review时手动替换不稳定的选择器。Cursor生成后,花5分钟检查每个定位策略——这个时间比手写30分钟值

坑2:Appium context切换容易遗漏

混合App(原生+WebView)在测试中需要频繁切换context。Cursor如果不知道是混合App,生成的代码可能只在NATIVE_APP中操作,导致WebView中的元素找不到

解决:在Prompt中明确说”这是混合App,WebView部分需要switch_to.context(‘WEBVIEW’)”。更好的做法是写进.cursorrules:所有Appium脚本默认处理context切换

坑3:过度依赖AI导致用例设计能力退化

这是最隐蔽的坑。当你习惯了”说一句话就出代码”,可能跳过测试用例设计——等价类没分、边界值没测、异常路径没覆盖。代码很快,但测试质量在下降

解决:坚持”先设计再生成”——先用等价类/边界值法列出测试点(纸笔或思维导图),再让Cursor根据你的测试点生成代码。AI负责”写”,你负责”想”

7.3 正确姿势:AI生成骨架 + 人工打磨细节

  1. AI生成
    框架结构、公共方法、基础定位
  2. 人工Review
    定位策略稳定性、断言完整性、等待策略合理性
  3. 人工补充
    业务特有逻辑、异常路径、数据驱动参数化
  4. AI修复
    日常维护中用Agent模式修复定位失效

八、总结与行动清单

一句话定位

Cursor是自动化测试的效率放大器——它把你从重复的”写模板代码”中解放出来,让你有更多时间做真正有价值的测试设计。但记住:它放大的是你的能力,如果你的设计能力为零,放大后还是零

3步上手计划

  1. 本周
    安装Cursor,用Composer生成一个Selenium登录测试脚本,跑通
  2. 第二周
    配置.cursorrules,生成完整POM框架,接入pytest和测试报告
  3. 第三周
    尝试Appium脚本生成(先Android后iOS),体验Agent修复

5条检查清单

💡 AI不会替代测试工程师,但会用AI的测试工程师,会替代不会用的。从今天开始,让Cursor成为你的测试脚手架