从零构建Web自动化测试体系:Selenium实战与框架设计

📅 2026/7/8 17:03:15 👁️ 阅读次数 📝 编程学习
从零构建Web自动化测试体系:Selenium实战与框架设计

1. 项目概述:为什么我们需要Web自动化测试?

如果你是一名Web开发者、测试工程师或者运维,我敢打赌你一定经历过这样的场景:每次代码更新后,你都需要手动打开Chrome、Firefox、Edge、Safari,甚至还要在手机模拟器上点来点去,检查登录按钮能不能按、表单提交后有没有跳转、页面布局在某个分辨率下会不会乱掉。一次两次还行,但项目迭代快的时候,每天可能要重复几十遍。更别提那些需要覆盖几十种浏览器和操作系统组合的复杂项目了,手动测试不仅耗时耗力,而且极易出错,毕竟人总会疲劳。

这就是Web自动化测试要解决的核心痛点:将那些重复、机械、易出错的Web功能验证工作,交给代码和工具去执行。它不仅仅是“写个脚本点点页面”,而是一套完整的工程实践,旨在提升软件交付的质量、速度和可靠性。想象一下,每次提交代码后,一套自动化脚本能在几分钟内,在数十种浏览器环境中并行执行成百上千个测试用例,并生成清晰的报告,告诉你哪个功能在哪个环境下失败了。这不仅能解放你的双手,更能让你对产品质量有前所未有的掌控力。

本教程的目标,就是带你从零开始,构建一套属于你自己的、可落地的Web自动化测试体系。我不会只讲Selenium的API怎么用,那太浅了。我会深入拆解自动化测试的核心设计思想、工具链选型、框架搭建、脚本编写技巧以及如何与CI/CD流水线集成,让你不仅能“写”出测试,更能“设计”出高效、稳定、可维护的自动化测试方案。无论你是想提升个人项目的质量,还是为团队引入自动化测试实践,这篇文章都将提供一条清晰的路径。

2. 自动化测试的核心思想与架构设计

在动手写第一行代码之前,我们必须先理清思路。Web自动化测试不是漫无目的地录制回放,而是一个有明确目标和分层设计的系统工程。

2.1 自动化测试的“金字塔”模型

一个健康的自动化测试体系应该像一座金字塔:

  • 底层(占比最大,约70%):单元测试(Unit Tests)。针对函数、方法、组件等最小可测试单元进行测试。速度快、稳定性高、定位问题精准。对于Web前端,这可能意味着用Jest、Mocha测试你的工具函数或React/Vue组件。
  • 中层(占比约20%):集成测试(Integration Tests)。测试多个模块或服务之间的交互。在Web语境下,这常常是API接口测试,使用像Supertest、Postman或专门的API测试框架来验证前后端数据交互是否正确。
  • 顶层(占比最小,约10%):端到端测试(End-to-End Tests, E2E)。也就是我们通常说的“Web UI自动化测试”。它模拟真实用户操作浏览器,从打开网页、点击、输入到验证结果。Selenium、Cypress、Playwright等都是这个层面的工具。它的价值在于验证完整业务流程,但缺点是速度慢、脆弱(页面结构一变就容易失败)、维护成本高。

核心原则:我们应该把大部分精力放在编写快速、稳定的单元和集成测试上,用尽可能少的E2E测试来覆盖最关键的用户旅程。试图用E2E测试覆盖所有功能点,是投入产出比最低、最令人沮丧的做法。

2.2 Web UI自动化测试的核心组件

一套完整的Web UI自动化测试方案通常包含以下几个部分:

  1. 测试框架(Test Framework):提供测试用例的组织、运行和断言能力。例如:JUnit(Java)、TestNG(Java)、pytest(Python)、Jest/Mocha(JavaScript)。
  2. 浏览器自动化驱动(Browser Driver):与真实浏览器交互的核心。最著名的是Selenium WebDriver,它遵循W3C标准,提供了一套统一的API来控制不同浏览器。此外,还有基于Chromium的Puppeteer(Google)和跨浏览器的Playwright(Microsoft),它们提供了更现代、更强大的API。
  3. 编程语言绑定(Language Bindings):让你能用熟悉的编程语言(Python、Java、JavaScript、C#等)调用WebDriver的API。
  4. 断言库(Assertion Library):用于验证测试结果是否符合预期。如:assert(Python内置)、Chai(JS)、Hamcrest(Java)。
  5. 报告生成器(Reporter):生成美观的测试报告,便于查看结果和分析失败原因。如:Allure、ExtentReports、pytest-html。
  6. 持续集成/持续部署(CI/CD)集成:将自动化测试集成到Jenkins、GitLab CI、GitHub Actions等流程中,实现代码提交后自动触发测试。

2.3 工具选型:Selenium vs. Cypress vs. Playwright

这是当前最主流的三个选择,各有优劣:

  • Selenium WebDriver行业标准,兼容性之王。支持所有主流浏览器(Chrome, Firefox, Safari, Edge, Opera等),支持多种编程语言。生态庞大,社区成熟。缺点是配置稍复杂,API相对底层,编写稳定、高效的测试脚本需要更多经验。适合需要覆盖广泛浏览器矩阵、技术栈多样的大型企业级项目。
  • Cypress前端开发者之友。它运行在浏览器内部,测试代码和应用程序运行在同一个循环中,因此执行速度极快,可以访问浏览器上下文(如网络请求、本地存储),调试体验无与伦比(时间旅行、实时重载)。但最大的限制是只支持Chromium系浏览器和Firefox,且无法轻松切换到另一个标签页或操作多个浏览器域。适合以Chrome为主要目标、追求开发体验和速度的前端项目。
  • Playwright微软出品的后起之秀。它吸取了Puppeteer(仅限Chrome)和Selenium的优点,支持Chromium、Firefox和WebKit(Safari引擎),提供了非常强大且稳定的API,例如自动等待、网络拦截、文件上传、跨域处理等。它同时支持无头(Headless)和有头模式,且并行执行效率高。是目前综合实力非常强的选择,尤其适合新项目。

我的选择建议:

  • 如果你是初学者,想快速上手并看到成果,从Playwright开始体验最好,它的API设计非常友好。
  • 如果你的项目必须覆盖Safari或IE(如果还有的话),或者团队技术栈是Java/.NET,Selenium仍是稳妥的选择。
  • 如果你的项目是纯前端SPA,且团队对Chrome覆盖率要求高,追求极致的开发调试体验,Cypress很棒。

在本教程中,我将以Selenium(Python语言绑定)作为主线进行讲解,因为它的普适性最强,原理也最具代表性。理解了Selenium,再学习Playwright或Cypress会非常容易。

3. 环境搭建与第一个自动化脚本

理论说再多不如动手。让我们从搭建环境开始,写出第一个能真正运行的自动化脚本。

3.1 基础环境准备

  1. 安装Python:确保你的系统安装了Python(建议3.7+)。可以去python.org下载。
  2. 安装Selenium库:通过pip安装Selenium的Python客户端库。
    pip install selenium
  3. 下载浏览器驱动(WebDriver):这是Selenium控制浏览器的桥梁。驱动版本必须与你的浏览器版本匹配!
    • Chrome驱动(ChromeDriver):前往 ChromeDriver官网 下载对应版本。
    • Firefox驱动(GeckoDriver):前往 GeckoDriver GitHub Releases 下载。
    • Edge驱动(Microsoft WebDriver):如果你使用Edge,需从 Microsoft Edge Developer 下载。

关键步骤:将下载的驱动(如chromedriver.exegeckodriver)放在一个目录下,并将该目录添加到系统的PATH环境变量中。这是为了让Selenium能够找到它。一个更简单的做法是,将驱动文件直接放在你的项目根目录下,然后在代码中指定路径。

3.2 编写并运行第一个测试脚本

让我们创建一个最简单的脚本,用Chrome打开百度首页,搜索一个关键词,并验证搜索结果标题。

创建一个文件,命名为first_test.py

from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time # 1. 创建WebDriver实例,启动浏览器 # 如果chromedriver已在PATH中,可以直接写 webdriver.Chrome() # 如果放在项目目录,需要指定路径:webdriver.Chrome(executable_path='./chromedriver') driver = webdriver.Chrome() # 这会打开一个真实的Chrome窗口 try: # 2. 导航到目标网址 driver.get("https://www.baidu.com") print(f"当前页面标题是:{driver.title}") # 3. 定位页面元素并与之交互 # 通过ID定位搜索框 search_box = driver.find_element(By.ID, "kw") # 在搜索框中输入文本 search_box.send_keys("Selenium自动化测试") # 模拟按下回车键 search_box.send_keys(Keys.RETURN) # 4. 等待并验证结果 # 使用显式等待,等待搜索结果的第一条链接出现(最多等10秒) # 这里我们等待一个包含特定class的div出现,这通常是搜索结果容器 wait = WebDriverWait(driver, 10) # 假设我们等待第一个搜索结果的标题链接出现 # 注意:百度的页面结构可能变化,这个选择器可能需要调整 first_result = wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, "div.result h3 a")) ) print(f"第一个搜索结果是:{first_result.text}") # 5. 一个简单的断言:检查页面标题是否包含搜索词 assert "Selenium自动化测试" in driver.title print("测试通过!页面标题包含‘Selenium自动化测试’") # 为了看清结果,等待3秒 time.sleep(3) finally: # 6. 关闭浏览器,释放资源 # driver.quit() 会关闭所有窗口并结束WebDriver会话 # driver.close() 只关闭当前窗口,如果只有一个窗口,效果相同 driver.quit()

逐行解析与注意事项:

  • webdriver.Chrome():初始化Chrome浏览器驱动。如果看到报错‘chromedriver’ executable needs to be in PATH,说明系统找不到驱动。请按3.1节所述处理。
  • driver.get(url):这是导航命令,会让浏览器加载指定URL。务必确保URL包含协议(http/https)
  • find_element(By.ID, “kw”):这是元素定位,是自动化测试的基石。By.ID表示通过HTML元素的id属性定位。百度的搜索框id就是kw。如果元素没有ID,我们还可以用By.NAME,By.CLASS_NAME,By.CSS_SELECTOR,By.XPATH等。
  • send_keys(“text”):向输入框输入文本。Keys.RETURN是模拟键盘回车键。
  • WebDriverWait(driver, 10).until(...):这是显式等待。Web页面加载是动态的,元素可能不会立即出现。显式等待会让WebDriver等待某个条件成立(如元素出现、可点击等),最多等待指定时间(这里是10秒)。强烈建议永远使用显式等待来代替time.sleep(),除非是等待动画等非条件性场景。time.sleep(5)是固定等待5秒,无论页面是否准备好,这会造成时间浪费或等待不足。
  • assert ... in driver.title:一个简单的Python断言,用于验证测试结果。在实际项目中,我们会使用测试框架(如pytest)更强大的断言功能。
  • driver.quit()非常重要!必须在测试结束时调用,它会关闭浏览器并终止WebDriver进程。如果不调用,后台可能会残留大量浏览器进程。

运行脚本:在终端中,进入脚本所在目录,执行:

python first_test.py

你应该会看到Chrome浏览器自动打开,访问百度,输入搜索词,跳转到结果页,然后在控制台打印信息,最后浏览器关闭。

实操心得:第一次运行很可能失败。常见原因:1) 驱动未正确配置;2) 浏览器版本与驱动不匹配;3) 页面元素定位器失效(百度页面改版了)。定位器失效是自动化测试中最常见的问题。你需要使用浏览器的开发者工具(F12)来检查元素的真实属性。可以尝试改用By.NAME定位wd,或者使用更稳定的CSS选择器。

4. 深入核心:元素定位与页面交互

元素定位是自动化脚本的“手”和“眼”。定位不准,一切操作都是空谈。

4.1 八大定位策略详解

Selenium WebDriver 提供了8种定位策略(By类):

  1. By.ID:通过元素的id属性。id在理想情况下应该是唯一的,定位最快、最可靠。首选
  2. By.NAME:通过元素的name属性。常用于表单元素。
  3. By.CLASS_NAME:通过元素的class属性。注意,一个元素可能有多个class,这里匹配的是完整的class字符串。
  4. By.TAG_NAME:通过标签名,如div,input,a。通常不唯一,需结合其他方法筛选。
  5. By.LINK_TEXT:通过超链接的完整可见文本定位。如<a href=”...”>登录</a>,可以用By.LINK_TEXT, “登录”
  6. By.PARTIAL_LINK_TEXT:通过超链接的部分可见文本定位。如上例也可用By.PARTIAL_LINK_TEXT, “录”。但需注意歧义。
  7. By.CSS_SELECTOR功能强大,推荐使用。使用CSS选择器语法定位,非常灵活。例如:
    • #kw(ID选择器)
    • .s_ipt(类选择器)
    • input[name=‘wd’](属性选择器)
    • div#content > h1(子元素选择器)
  8. By.XPATH功能最强大,但也最复杂。使用XML路径语言定位,可以在整个DOM树中进行非常精细的查询。例如:
    • //input[@id=‘kw’](查找任意层级下id为kw的input)
    • //div[@class=‘result’]//a[contains(text(), ‘教程’)](查找class为result的div下,链接文本包含“教程”的a标签)

定位策略选择优先级建议:ID>NAME>CSS_SELECTOR>XPATH> 其他。CSS_SELECTOR在大多数现代浏览器中解析速度比XPATH快,且语法更简洁。XPATH在应对复杂结构(如根据兄弟节点定位)时无可替代。

4.2 高级定位技巧与等待策略

1. 处理动态元素与等待:现代Web应用大量使用AJAX和前端框架,元素是动态加载的。直接find_element很可能因元素未加载而抛出NoSuchElementException

  • 隐式等待(Implicit Wait)driver.implicitly_wait(10)。设置一个全局等待时间,在查找任何元素时,如果没立即找到,WebDriver会轮询DOM直到超时。缺点:不够灵活,对某些条件(如元素可点击)无效。
  • 显式等待(Explicit Wait)推荐使用。针对特定条件进行等待。
    from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 等待最多10秒,直到元素可点击 element = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, “submit-btn”)) ) element.click()
    常用的EC(预期条件)包括:
    • presence_of_element_located:元素出现在DOM中(不一定可见)。
    • visibility_of_element_located:元素可见(宽高大于0)。
    • element_to_be_clickable:元素可见且可点击。
    • title_contains:页面标题包含某文字。
    • alert_is_present:出现了JS警告框。

2. 处理iframe:如果目标元素在<iframe>内,你必须先切换到该iframe上下文。

# 通过ID或索引切换 driver.switch_to.frame(“iframe_id”) # 操作iframe内的元素... # 操作完毕后切回主文档 driver.switch_to.default_content()

3. 处理弹窗/Alert:

# 等待alert出现并获取它 alert = WebDriverWait(driver, 5).until(EC.alert_is_present()) # 获取alert文本 print(alert.text) # 点击“确定” alert.accept() # 或者点击“取消” # alert.dismiss()

4. 执行JavaScript:当标准API无法完成操作时(如滚动页面、修改元素属性),可以执行JS。

# 滚动到页面底部 driver.execute_script(“window.scrollTo(0, document.body.scrollHeight);”) # 获取元素背景色 color = driver.execute_script(“return arguments[0].style.backgroundColor;”, element) # 点击元素(有时比 element.click() 更可靠) driver.execute_script(“arguments[0].click();”, element)

避坑指南:元素定位的稳定性

  • 避免使用绝对XPath:如/html/body/div[3]/div[2]/form/input[1]。页面结构微调就会导致定位失败。尽量使用相对路径或基于属性的定位。
  • 使用有意义的属性:优先选择id,name,>from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class LoginPage: # 定位器 (Locators) USERNAME_INPUT = (By.ID, “username”) PASSWORD_INPUT = (By.ID, “password”) LOGIN_BUTTON = (By.ID, “loginBtn”) ERROR_MESSAGE = (By.CLASS_NAME, “error”) def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(driver, 10) def load(self, url): self.driver.get(url) return self def enter_username(self, username): user_elem = self.wait.until(EC.visibility_of_element_located(self.USERNAME_INPUT)) user_elem.clear() user_elem.send_keys(username) return self # 支持链式调用 def enter_password(self, password): pwd_elem = self.wait.until(EC.visibility_of_element_located(self.PASSWORD_INPUT)) pwd_elem.clear() pwd_elem.send_keys(password) return self def click_login(self): login_elem = self.wait.until(EC.element_to_be_clickable(self.LOGIN_BUTTON)) login_elem.click() def get_error_message(self): try: error_elem = self.wait.until(EC.visibility_of_element_located(self.ERROR_MESSAGE)) return error_elem.text except: return None # 如果没有错误信息,返回None
  • 创建测试脚本test_login.py
    import pytest from selenium import webdriver from login_page import LoginPage class TestLogin: @pytest.fixture(scope=”class”) def driver(self): # 初始化驱动,整个测试类只执行一次 driver = webdriver.Chrome() driver.implicitly_wait(5) yield driver driver.quit() @pytest.fixture def login_page(self, driver): # 每个测试用例都获得一个干净的登录页面 page = LoginPage(driver) page.load(“http://your-app.com/login”) return page def test_successful_login(self, login_page): login_page.enter_username(“valid_user”) .enter_password(“valid_pass”) .click_login() # 断言登录成功,例如跳转到首页,URL包含‘dashboard’ assert “dashboard” in login_page.driver.current_url def test_failed_login_wrong_password(self, login_page): login_page.enter_username(“valid_user”) .enter_password(“wrong_pass”) .click_login() error_msg = login_page.get_error_message() assert error_msg is not None assert “密码错误” in error_msg
  • POM的优势:

    • 高可维护性:UI变更只需修改对应的页面对象类。
    • 高可读性:测试用例读起来像自然语言,业务逻辑清晰。
    • 低冗余:页面操作逻辑被复用,避免代码重复。
    • 便于协作:页面对象可以由专人维护,测试人员专注于编写用例。

    5.2 集成测试框架(以pytest为例)

    pytest是Python生态中强大且流行的测试框架。它比自带的unittest更简洁,功能更丰富。

    安装pytest:

    pip install pytest

    使用pytest运行测试:在项目根目录下,直接运行:

    pytest

    pytest会自动发现以test_开头或_test结尾的文件和函数,并执行它们。

    pytest的强大特性:

    • Fixture:如上例中的driverlogin_page。用于提供测试依赖(如WebDriver实例、页面对象、测试数据),并管理其生命周期(setup/teardown)。scope参数可以控制Fixture的作用域(function, class, module, session)。
    • 参数化测试:用一组数据驱动同一个测试用例。
      import pytest @pytest.mark.parametrize(“username, password, expected”, [ (“user1”, “pass1”, True), (“user1”, “wrong”, False), (“”, “pass1”, False), ]) def test_login_parametrized(login_page, username, password, expected): # ... 使用参数执行测试并断言
    • 丰富的插件生态:如pytest-html(生成HTML报告)、pytest-xdist(并行测试)、pytest-rerunfailures(失败重试)。

    5.3 生成测试报告

    清晰的报告是自动化测试价值的直观体现。使用pytest-html可以轻松生成美观的HTML报告。

    安装与使用:

    pip install pytest-html

    运行测试并生成报告:

    pytest --html=report.html --self-contained-html

    --self-contained-html参数会将CSS和图片嵌入到单个HTML文件中,方便分享。

    报告会包含测试通过/失败的数量、每个测试用例的执行时长、失败用例的错误堆栈信息等,非常直观。

    6. 高级主题与最佳实践

    6.1 跨浏览器测试与云端测试平台

    你不可能在本地安装所有浏览器和版本。这时就需要云端测试平台。

    • Selenium Grid:Selenium官方的分布式测试解决方案。你可以搭建一个Hub和多个Node(安装了不同浏览器),测试脚本将请求发送给Hub,由Hub分配执行。
    • 第三方云测平台:如BrowserStackSauce LabsLambdaTest。它们提供了海量的真实浏览器/设备/操作系统组合,你无需自己维护基础设施。它们通常提供与Selenium WebDriver兼容的远程URL。

    使用BrowserStack运行脚本示例:你需要修改WebDriver的初始化,指向云端的远程地址。

    from selenium import webdriver from selenium.webdriver.common.keys import Keys desired_cap = { ‘browser’: ‘Chrome’, ‘browser_version’: ‘latest’, ‘os’: ‘Windows’, ‘os_version’: ‘10’, ‘name’: ‘Bstack-[Python] Sample Test’ # 测试名称 } driver = webdriver.Remote( command_executor=’https://USERNAME:ACCESS_KEY@hub.browserstack.com/wd/hub’, desired_capabilities=desired_cap ) # 之后的代码和本地运行完全一样 driver.get(“http://www.google.com”) # ... driver.quit()

    USERNAMEACCESS_KEY替换为你在BrowserStack账户中获取的密钥。

    6.2 测试数据管理

    测试数据(如用户名、商品信息)不应该硬编码在测试脚本中。

    • 外部文件:使用JSON、YAML、CSV或Excel文件存储测试数据。
    • 数据库:对于复杂或需要动态生成的数据,可以连接测试数据库。
    • Faker库:用于生成随机的、逼真的测试数据(如姓名、地址、邮箱)。
      pip install Faker
      from faker import Faker fake = Faker(‘zh_CN’) test_username = fake.user_name() test_email = fake.email()

    6.3 失败处理与截图

    测试失败时,一个清晰的现场截图价值千金。

    import pytest from selenium import webdriver import os from datetime import datetime @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): # 获取测试结果的钩子函数 outcome = yield rep = outcome.get_result() # 只处理测试失败的情况 if rep.when == “call” and rep.failed: # 获取测试用例中的driver fixture try: driver = item.funcargs[‘driver’] except KeyError: print(“无法获取driver,跳过截图”) return # 创建截图目录 screenshot_dir = “./screenshots” os.makedirs(screenshot_dir, exist_ok=True) # 生成带时间戳的文件名 timestamp = datetime.now().strftime(“%Y%m%d_%H%M%S”) test_name = item.name file_name = f”{test_name}_{timestamp}.png” file_path = os.path.join(screenshot_dir, file_name) # 截图 driver.save_screenshot(file_path) print(f”测试失败,截图已保存至:{file_path}”)

    将这个函数放在conftest.py文件中,pytest会自动调用它。这样,任何测试失败时,都会自动截取当前浏览器画面并保存。

    6.4 与CI/CD集成(以GitHub Actions为例)

    自动化测试只有集成到开发流程中才能发挥最大价值。以下是一个简单的GitHub Actions工作流配置,在每次代码推送时运行自动化测试。

    在项目根目录创建.github/workflows/test.yml

    name: Web UI Automation Tests on: [push, pull_request] # 在推送代码或创建PR时触发 jobs: test: runs-on: ubuntu-latest # 在Ubuntu系统上运行 steps: - name: Checkout code uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: ‘3.9’ - name: Install dependencies run: | pip install -r requirements.txt # 假设你的依赖写在requirements.txt里 # 安装Chrome浏览器和ChromeDriver sudo apt-get update sudo apt-get install -y chromium-browser chromium-chromedriver - name: Run tests with pytest run: | # 设置无头模式运行,并指定ChromeDriver路径 export CHROME_BIN=/usr/bin/chromium-browser export CHROMEDRIVER_PATH=/usr/bin/chromedriver pytest --html=report.html --self-contained-html - name: Upload test report uses: actions/upload-artifact@v3 if: always() # 即使测试失败也上传报告 with: name: pytest-report path: report.html

    这样,每次提交后,GitHub都会自动在一个干净的Ubuntu环境中安装环境、运行你的测试,并将HTML报告作为构建产物保存,供你下载查看。

    7. 常见问题排查与调试技巧

    即使经验丰富,也会遇到脚本失败。以下是快速排查的思路:

    1. NoSuchElementException(元素找不到)

      • 首先检查:你的定位器(Selector)在当前页面是否真的存在?用浏览器开发者工具(F12 -> Elements)的搜索功能(Ctrl+F)验证。
      • 可能原因
        • 页面尚未加载完成 →增加显式等待
        • 元素在<iframe><shadow-root>内 →切换上下文
        • 元素是动态生成的,ID/Class是随机字符串 → 尝试用更稳定的属性(如>driver.set_page_load_timeout(30) driver.set_script_timeout(30)
        • 文件路径问题:CI服务器的工作目录可能与本地不同。上传文件时,使用绝对路径或确保路径正确。
    2. 脚本运行慢

      • 优化等待:用显式等待替代固定的time.sleep
      • 减少不必要的操作:如非必要,不要每次测试都从头登录。可以使用Fixture在会话级别登录一次。
      • 并行执行:使用pytest-xdist插件并行运行多个测试。
      • 使用无头模式:在不需要观察浏览器界面时,使用无头模式可以显著提升速度。
        from selenium.webdriver.chrome.options import Options options = Options() options.add_argument(‘--headless’) options.add_argument(‘--disable-gpu’) driver = webdriver.Chrome(options=options)

    终极调试技巧:当一切都不奏效时

    • 暂停测试:在出问题的代码行前插入input(“按回车继续...”),然后手动操作浏览器,检查页面状态。
    • 截图+源码:在失败点前后截图,并打印当前页面的HTML源码 (driver.page_source)。
    • 使用pdb或IDE调试器:设置断点,单步执行,查看变量状态。

    Web自动化测试是一个需要耐心和细致的工作。它不仅仅是技术活,更是对软件质量保障体系的深入理解。从编写第一个简单的脚本,到构建一个健壮的、与CI/CD深度集成的自动化测试套件,这条路充满挑战,但回报也是巨大的——它将你从重复劳动中解放出来,让你有更多时间去做更有价值的探索性测试和复杂场景设计。记住,自动化测试的目标不是取代手动测试,而是将测试人员从重复劳动中解放出来,让他们去做机器做不到的事情