SeleniumBase与Cypress Real World App自动化测试实践

发布时间:2026/11/4 23:18:31
SeleniumBase与Cypress Real World App自动化测试实践

1. 项目概述:SeleniumBase与Cypress Real World App的自动化测试实践

最近在尝试使用SeleniumBase框架对Cypress Real World App这个开源项目进行自动化测试时,遇到了几个典型的前后端交互问题。作为一款模拟真实金融场景的测试应用,Cypress Real World App包含了用户注册、登录、转账等完整业务流程,是学习自动化测试的优秀素材。而SeleniumBase作为基于Python的测试框架,它整合了Selenium WebDriver和pytest的优势,特别适合需要复杂交互的Web应用测试。

在测试过程中,我主要遇到了两个核心问题:注册后不自动跳转登录页面的前端路由问题,以及测试用例间登录状态残留导致的流程失败。这两个问题看似简单,但涉及到了前后端联调、HTTP代理配置、浏览器存储机制等多个技术点,对测试脚本的稳定性影响很大。下面我将详细记录问题排查过程和解决方案,这些经验对于任何使用Selenium或类似工具进行Web自动化测试的开发者都值得参考。

2. 环境准备与项目配置

2.1 测试环境搭建

要复现这个测试场景,需要准备以下环境:

  • Python 3.8+环境(推荐使用virtualenv创建隔离环境)
  • Node.js 16+(用于运行Cypress Real World App前端)
  • Java 8+(部分后端服务依赖)
  • 最新版Chrome浏览器

安装核心测试依赖:

pip install seleniumbase pytest

克隆Cypress Real World App仓库并启动:

git clone https://github.com/cypress-io/cypress-realworld-app.git cd cypress-realworld-app npm install npm start

2.2 SeleniumBase测试脚本结构

典型的测试文件结构如下:

tests/ ├── conftest.py # pytest配置和fixture ├── test_login.py # 登录相关测试用例 └── pages/ # Page Object模式目录 ├── base.py ├── login.py └── register.py

基础测试用例示例:

from seleniumbase import BaseCase class LoginTest(BaseCase): def test_user_registration(self): self.open("http://localhost:3000") self.type('input[name="username"]', "testuser") self.type('input[name="password"]', "Pass1234") self.click('button[type="submit"]') self.assert_text("Welcome", "h1")

3. 注册跳转问题深度解析

3.1 问题现象与初步排查

当运行注册流程测试时,发现提交注册表单后页面没有自动跳转到登录页,而是停留在注册页且没有任何错误提示。通过Chrome开发者工具检查网络请求,发现POST /users请求返回了200状态码,但前端没有处理成功响应。

常见的排查方向:

  1. CORS跨域问题:检查响应头是否包含Access-Control-Allow-Origin
  2. 后端服务未启动:确认后端API是否正常运行
  3. 前端路由配置:检查注册成功后的重定向逻辑

3.2 根本原因定位

经过抓包分析和手动测试验证,发现问题出在前端代码的API请求地址配置上。在authMachine.ts文件中,存在硬编码的后端地址:

const resp = await httpClient.post( `http://localhost:${backendPort}/users`, payload );

这里有两个关键问题:

  1. backendPort变量没有正确从环境变量读取,导致实际请求发送到了前端开发服务器(3000端口)
  2. 使用了绝对路径而非相对路径,使得代理配置无法生效

3.3 解决方案实现

3.3.1 代码修改方案

最优解是修改authMachine.ts,使用相对路径并确保代理配置正确:

// 修改后的API调用 const resp = await httpClient.post("/users", payload);

同时需要完善vite.config.ts中的代理配置,避免硬编码端口:

proxy: { '^/(login|users|checkAuth|graphql|contacts|bankAccounts|transactions|likes|comments|notifications|bankTransfers|testData)': { target: `http://localhost:${env.VITE_BACKEND_PORT || '3001'}`, changeOrigin: true, rewrite: (path) => path, } }
3.3.2 测试脚本适配

在SeleniumBase测试中,我们需要增加对页面跳转的显式等待和断言:

def test_user_registration(self): self.open("http://localhost:3000/register") # 填写注册表单 self.type('input[name="firstName"]', "Test") self.type('input[name="lastName"]', "User") self.type('input[name="username"]', "testuser") self.type('input[name="password"]', "Pass1234") self.click('button[type="submit"]') # 显式等待跳转 self.wait_for_url_contains("/login", timeout=10) self.assert_text("Sign in", "h1")

重要提示:在实际测试中,应该使用环境变量管理后端地址,而不是硬编码在测试脚本中。可以通过pytest的fixture或conftest.py来集中管理测试配置。

4. 登录状态残留问题解决方案

4.1 问题现象分析

当连续运行多个测试用例时,发现第二个测试用例开始时,应用已经处于登录状态。这是因为浏览器保留了前一个测试的cookies、localStorage和sessionStorage。具体表现为:

  • 直接访问首页会被重定向到dashboard
  • 尝试注册新用户会提示"已登录"
  • 用户相关操作会使用前一个测试的用户凭证

4.2 浏览器存储机制解析

现代Web应用通常使用三种方式保持登录状态:

  1. Cookies:最常见的方式,可设置过期时间
  2. localStorage:持久化存储,除非手动清除
  3. sessionStorage:标签页级别的临时存储

在Cypress Real World App中,检查发现主要使用了:

  • JWT token存储在localStorage
  • 用户信息存储在Redux store
  • 部分配置信息使用sessionStorage

4.3 测试隔离方案

4.3.1 方案一:每次测试后清理存储
def tearDown(self): # 清除所有cookies self.driver.delete_all_cookies() # 清除localStorage和sessionStorage self.execute_script("window.localStorage.clear();") self.execute_script("window.sessionStorage.clear();") super().tearDown()
4.3.2 方案二:使用无痕模式

修改测试启动配置:

class LoginTest(BaseCase): @classmethod def setUpClass(cls): super().setUpClass() cls.driver = cls.get_driver(browser="chrome", incognito=True)
4.3.3 方案三:完全独立的测试会话

最可靠的方式是为每个测试启动全新的浏览器实例:

# conftest.py @pytest.fixture(scope="function") def browser(request): driver = webdriver.Chrome(options=chrome_options) yield driver driver.quit() # 测试用例 def test_example(browser): sb = BaseCase() sb.driver = browser sb.open("http://localhost:3000")

4.4 最佳实践建议

  1. 测试顺序设计:将需要未登录状态的测试(如注册)放在前面,已登录状态的测试放在后面
  2. 显式登出:在测试结束时主动调用登出API
  3. 使用独立测试账户:为每个测试生成唯一的用户名,避免冲突
  4. 并行测试隔离:当使用pytest-xdist并行运行时,确保每个worker有独立的环境配置

5. SeleniumBase高级测试技巧

5.1 元素定位策略优化

在测试金融类应用时,推荐使用以下定位策略:

# 好的实践 self.type('css=input[name="amount"]', "100") # 明确指定选择器类型 self.click('button:contains("Send Payment")') # 文本内容定位 # 避免的做法 self.type('//*[@id="app"]/div/div[2]/form/div[3]/input', "100") # 脆弱的XPath

5.2 等待机制最佳实践

金融应用常有异步操作,需要合理使用等待:

# 显式等待转账完成 self.wait_for_element_visible('div.transaction-complete', timeout=15) # 自定义等待条件 def balance_updated(self, amount): self.wait_for_text(f"${amount}", 'span.account-balance') # 轮询API结果 def wait_for_transaction(self, tx_id): for _ in range(10): status = get_transaction_status(tx_id) if status == "completed": return time.sleep(1) raise TimeoutError("Transaction not completed")

5.3 测试数据管理

对于转账等操作,建议使用工厂模式创建测试数据:

# test_data.py class TestDataFactory: @staticmethod def create_user(role="user"): return { "username": f"test_{uuid.uuid4().hex[:8]}", "password": "Secure123!", "email": f"test_{uuid.uuid4().hex[:8]}@example.com" } # 测试用例中使用 user = TestDataFactory.create_user() self.create_account_via_api(user) # 通过API快速创建测试账户

6. 常见问题排查指南

6.1 元素定位失败

现象:测试报告"Element not found"错误排查步骤:

  1. 使用Chrome开发者工具验证选择器
  2. 检查iframe嵌套情况
  3. 确认元素是否在Shadow DOM中
  4. 检查页面是否完全加载完成

6.2 异步操作超时

现象:等待元素超时解决方案:

# 调整全局等待时间 self.set_timeout(30) # 默认是10秒 # 使用更精确的等待条件 self.wait_for_element_present('div.alert-success')

6.3 跨域问题处理

当测试需要访问多个域名时:

# 启动浏览器时添加参数 chrome_options = webdriver.ChromeOptions() chrome_options.add_argument("--disable-web-security") chrome_options.add_argument("--allow-running-insecure-content")

6.4 测试稳定性提升技巧

  1. 启用重试机制:
@pytest.mark.flaky(reruns=2, reruns_delay=1) def test_payment(self): ...
  1. 失败时截图:
def test_example(self): try: # 测试步骤 except Exception as e: self.save_screenshot("failure.png") raise
  1. 视频录制(需要额外配置):
# pytest.ini [pytest] seleniumbase_recording = true

7. 项目经验总结

在实际测试Cypress Real World App的过程中,有几个关键经验值得分享:

  1. 前后端分离架构的测试需要特别注意API请求的路径和代理配置,相对路径比绝对路径更可靠。

  2. 测试隔离是自动化测试的核心原则之一,特别是对于有状态的应用,必须在测试之间清理浏览器状态。

  3. 等待策略需要根据实际业务场景调整,金融类操作通常需要更长的超时时间。

  4. 测试数据管理应该与应用架构解耦,通过工厂模式或API预创建数据比UI操作更高效。

  5. SeleniumBase的报告功能非常强大,合理使用截图、HTML报告和日志能极大提升调试效率。

最后分享一个实用技巧:在编写测试用例时,可以先用self.pause()方法暂停执行,然后手动检查页面状态,确认无误后再继续自动化流程。这个技巧在调试复杂交互时特别有用。