Selenium自动化测试实战:从零构建百度搜索自动化脚本

发布时间:2026/7/3 16:04:54
Selenium自动化测试实战:从零构建百度搜索自动化脚本 1. 项目概述如果你是一名测试工程师或者是一名想提升工作效率的开发者那么“自动化测试”这个词对你来说一定不陌生。但很多时候我们听到的更多是概念和框架真正动手时却不知从何开始或者写出来的脚本脆弱不堪一个页面元素的微小改动就能让它“罢工”。今天我就以一个最经典、最接地气的场景——“自动化百度搜索”为例带你从零开始手把手拆解Web自动化测试的完整流程。这不仅仅是一个“Hello World”式的演示我会把我在实际项目中踩过的坑、总结的经验以及如何构建一个健壮、可维护的自动化脚本的思考毫无保留地分享给你。无论你是想用自动化测试来保证产品质量还是想用它来解放双手做一些重复性的数据抓取或操作这篇文章都能给你一套可以直接“抄作业”的实战方案。2. 核心概念与工具选型在动手写代码之前我们必须先搞清楚两件事第一什么是Web自动化测试我们到底要用它来做什么第二面对琳琅满目的工具我们该如何选择2.1 Web自动化测试的本质与价值Web自动化测试简单说就是用程序模拟人在浏览器里的操作比如点击、输入、滚动、验证页面内容等。它的核心价值在于将重复、枯燥的回归测试工作交给机器从而提升效率与覆盖率一套脚本可以在几分钟内执行完人工需要数小时才能完成的测试用例并且可以7x24小时不间断运行极大地提高了测试覆盖率和执行频率。保证一致性人工测试难免会有疏忽和疲劳而机器每次执行都完全一致避免了人为误差。支持持续集成自动化测试脚本可以无缝集成到CI/CD流水线中每次代码提交后自动运行快速反馈质量问题是实现DevOps和敏捷开发的关键一环。对于我们今天的“百度搜索”实战其价值可以具体化为验证搜索功能是否正常、检查搜索结果的相关性、或者作为更复杂数据采集流程的第一步。理解了这个“为什么”我们写代码时目标才会更明确。2.2 主流工具对比与Selenium胜出理由市面上Web自动化测试工具不少比如Puppeteer、Cypress、Playwright以及老牌的Selenium。为什么我选择Selenium作为入门和实战的首选工具Selenium它是一个开源项目支持多种语言Java, Python, C#, JavaScript等几乎兼容所有现代浏览器。它的生态非常成熟社区庞大遇到问题基本都能找到解决方案。其核心原理是通过WebDriver协议与真实浏览器通信因此测试环境最贴近真实用户。Puppeteer/Playwright这两个是后起之秀由浏览器厂商Chrome/微软直接支持在速度和稳定性上有一定优势特别是对现代Web应用单页应用SPA的支持更好。但它们更偏向于Node.js生态。Cypress同样是一个优秀的现代测试框架开箱即用对前端开发者非常友好。但其运行机制与Selenium不同不支持同时驱动多个浏览器标签页或跨域操作有一定局限性。选择Selenium的理由普适性最强语言和浏览器支持最广学习资料最多是行业事实标准。掌握了Selenium再学其他工具会非常容易。最贴近真实用户驱动真实浏览器能测试到包括JavaScript渲染、CSS样式在内的完整用户体验这是无头浏览器或一些模拟器无法完全替代的。生态完善除了核心的WebDriver还有Selenium Grid用于分布式测试IDE用于录制回放以及众多成熟的框架如TestNG, JUnit, Pytest可以集成。对于初学者和大多数企业级应用测试从Selenium入手是稳妥且收益最大的选择。本次实战我们将使用Selenium with Python的组合因为Python语法简洁生态丰富非常适合快速实现自动化脚本。3. 环境搭建与核心配置详解工欲善其事必先利其器。环境搭建是第一步也是新手最容易卡住的地方。我会详细说明每一步并解释其作用。3.1 Python与Selenium库安装首先确保你的系统安装了Python建议3.7及以上版本。然后通过pip安装Selenium库这是最基础的一步。pip install selenium这个命令会从Python官方的包索引下载并安装selenium包。安装成功后你就能在Python代码中from selenium import webdriver了。3.2 WebDriver连接代码与浏览器的桥梁这是最关键也是最容易出错的一步。Selenium本身不能直接控制浏览器它需要通过一个名为“WebDriver”的中间件来发送指令。你需要为你要使用的浏览器下载对应的WebDriver。ChromeDriver用于Chrome/Edge新版访问 ChromeDriver官网 或国内的镜像站下载与你的Chrome浏览器大版本号一致的驱动。比如你Chrome是115版本就找115.x.x.x的ChromeDriver。GeckoDriver用于Firefox访问 GeckoDriver GitHub发布页 下载。Microsoft Edge Driver如果使用Edge需从 微软开发者网站 下载。下载后你需要告诉Selenium这个驱动放在哪里。有三种常见方式放入系统PATH将下载的驱动文件如chromedriver.exe放在系统环境变量PATH包含的目录下如C:\Windows\或/usr/local/bin。这是最推荐的方式一劳永逸。指定绝对路径在代码中通过webdriver.Chrome(executable_path‘你的路径/chromedriver’)指定。但注意最新版Selenium已弃用executable_path参数推荐使用Service对象。使用WebDriver Manager强烈推荐这是一个第三方库可以自动帮你下载、匹配和管理WebDriver省去手动下载和版本匹配的烦恼。安装pip install webdriver-manager。使用时from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager service Service(ChromeDriverManager().install()) driver webdriver.Chrome(serviceservice)实操心得在团队协作或CI/CD环境中强烈推荐使用WebDriver Manager或将驱动放入PATH。这能避免因团队成员浏览器版本不一致导致的“在我机器上是好的”这类问题。手动指定路径的方式只适合临时调试。3.3 编写你的第一个自动化脚本打开百度环境准备好后我们来写一个最简单的脚本打开百度首页。from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager import time # 1. 创建WebDriver服务使用WebDriver Manager自动管理驱动 service Service(ChromeDriverManager().install()) # 2. 实例化浏览器驱动对象这里使用Chrome driver webdriver.Chrome(serviceservice) # 3. 控制浏览器窗口可选 driver.maximize_window() # 最大化窗口确保元素可见 # 4. 打开目标网址 driver.get(https://www.baidu.com) # 5. 等待几秒以便观察效果 time.sleep(3) # 6. 获取当前页面标题并打印 print(当前页面标题是, driver.title) # 7. 关闭浏览器窗口 driver.quit()运行这段代码你应该能看到一个Chrome浏览器自动打开访问百度首页然后在控制台打印出“当前页面标题是百度一下你就知道”最后关闭。代码解析driver对象是你控制浏览器的“遥控器”所有后续操作都通过它进行。get(url)方法用于导航到指定URL。title属性用于获取当前页面的标题。quit()方法会关闭所有由该驱动打开的窗口并结束驱动进程。与之类似的close()方法只关闭当前标签页。务必在脚本最后调用quit()来清理资源否则后台可能会残留浏览器进程。4. 元素定位自动化操作的基石自动化测试的核心是“找到元素然后操作它”。Selenium提供了多达8种元素定位方式掌握它们是你从入门到精通的关键。4.1 八大定位策略详解假设我们要定位百度的搜索输入框那个长长的文本框。ID定位最优先使用的方式因为ID在HTML中通常是唯一的。search_box driver.find_element(By.ID, “kw”) # 百度输入框的id就是‘kw’Name定位类似于ID但Name可能不唯一。search_box driver.find_element(By.NAME, “wd”) # 百度输入框的name是‘wd’Class Name定位通过CSS类名定位。注意一个元素可能有多个类名且类名常不唯一。# 假设输入框有一个类名 ‘s_ipt’ search_box driver.find_element(By.CLASS_NAME, “s_ipt”)Tag Name定位通过HTML标签名定位如input,div。通常用于查找一组同类元素。inputs driver.find_elements(By.TAG_NAME, “input”) # 找到页面上所有input元素Link Text定位专门用于定位超链接a标签通过链接的完整文本。news_link driver.find_element(By.LINK_TEXT, “新闻”) # 定位文本为“新闻”的链接Partial Link Text定位通过链接的部分文本定位。news_link driver.find_element(By.PARTIAL_LINK_TEXT, “闻”) # 也能定位到“新闻”链接CSS Selector定位功能强大且灵活语法与前端CSS选择器一致。是除了ID之外最常用的定位方式。# 通过id search_box driver.find_element(By.CSS_SELECTOR, “#kw”) # 通过class search_box driver.find_element(By.CSS_SELECTOR, “.s_ipt”) # 通过属性 search_box driver.find_element(By.CSS_SELECTOR, “input[name‘wd’]”) # 组合定位 search_box driver.find_element(By.CSS_SELECTOR, “form#form input#kw”)XPath定位最强大的定位方式可以遍历XML/HTML文档的任何节点。当其他方式都失效时XPath往往能救场。# 绝对路径脆弱不推荐 search_box driver.find_element(By.XPATH, “/html/body/div[1]/div[1]/div[5]/div[2]/div/form/span[1]/input”) # 相对路径属性推荐 search_box driver.find_element(By.XPATH, “//input[id‘kw’]”) # 使用文本内容定位 news_link driver.find_element(By.XPATH, “//a[text()‘新闻’]”) # 包含某些属性或文本 search_box driver.find_element(By.XPATH, “//input[contains(class, ‘s_ipt’)]”)注意事项find_element返回找到的第一个匹配元素find_elements返回一个包含所有匹配元素的列表。定位不到元素时find_element会抛出NoSuchElementException异常。4.2 如何选择定位策略一个优先级建议在实际项目中为了脚本的稳定性和可读性我通常会遵循以下优先级首选ID唯一且查找速度最快。次选CSS Selector灵活、速度快且现代前端开发中CSS选择器很常见。谨慎使用XPathXPath功能强大但性能相对较差且容易因页面结构微小变动而失效尤其是绝对路径。仅在复杂层级或需要根据文本定位时使用。避免使用不稳定的属性如自动生成的类名class‘js-xxxx-123’、索引位置如div[3]这些在页面迭代时极易变化。为关键元素添加测试专用属性在开发阶段可以和前端工程师约定为重要的可操作元素添加>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 from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager import time # 初始化驱动 service Service(ChromeDriverManager().install()) driver webdriver.Chrome(serviceservice) driver.maximize_window() wait WebDriverWait(driver, 10) # 创建显式等待对象最多等10秒 try: # 1. 访问百度 driver.get(https://www.baidu.com) print(已访问百度首页) # 2. 定位搜索框并输入关键词 # 使用显式等待确保元素加载完成再操作 search_input wait.until( EC.presence_of_element_located((By.ID, kw)) ) search_input.clear() # 清空输入框避免残留内容 search_input.send_keys(自动化测试) # 输入文本 print(已输入搜索关键词自动化测试) # 3. 定位搜索按钮并点击 # 同样使用显式等待 search_button wait.until( EC.element_to_be_clickable((By.ID, su)) ) search_button.click() print(已点击搜索按钮) # 4. 等待搜索结果页面加载完成 # 可以等待某个结果元素出现作为页面加载完成的标志 wait.until( EC.presence_of_element_located((By.CSS_SELECTOR, “div.result”)) ) print(“搜索结果页面加载完成”) # 5. 获取搜索结果 # 百度搜索结果的标题通常包含在h3标签内且class包含‘t’ result_titles driver.find_elements(By.CSS_SELECTOR, “h3.t”) print(f“共找到 {len(result_titles)} 条搜索结果”) for index, title_element in enumerate(result_titles, start1): # 获取标题文本 title_text title_element.text.strip() # 获取链接。注意标题的父级a标签才是真正的链接 link_element title_element.find_element(By.XPATH, “./parent::a”) link_url link_element.get_attribute(“href”) print(f“{index}. 标题{title_text}”) print(f“ 链接{link_url}”) print(“-” * 50) # 6. 可选翻页操作 # 定位“下一页”按钮并点击 # next_page_button driver.find_element(By.LINK_TEXT, “下一页 ”) # next_page_button.click() # print(“已点击下一页”) # time.sleep(2) # 等待翻页加载 except Exception as e: print(f“执行过程中出现错误{e}”) # 可以在这里截图方便排查问题 driver.save_screenshot(“error_screenshot.png”) finally: # 确保无论是否出错最后都关闭浏览器 time.sleep(3) # 最后等待3秒方便观察结果 driver.quit() print(“浏览器已关闭”)5.2 核心强化三种等待机制详解Web自动化测试中等待是保证脚本稳定性的灵魂。页面加载、元素出现、AJAX请求完成都需要时间。不当的等待会导致“元素未找到”的错误。Selenium主要有三种等待方式强制等待time.sleep(seconds)是什么让脚本无条件暂停指定秒数。缺点时间固定无论页面是否加载完成都要等效率低下。网络或环境变化时固定的时间可能不够或浪费。使用场景仅用于调试或在极少数明确知道需要固定间隔的操作如等待动画完成时使用。生产脚本中应尽量避免。隐式等待driver.implicitly_wait(seconds)是什么为driver对象设置一个全局的等待时间。在查找任何元素时如果元素没有立即出现WebDriver会轮询DOM默认每0.5秒直到找到该元素或超时。优点设置一次对整个driver生命周期有效。缺点不够灵活只能用于元素查找无法处理其他条件如元素可点击、元素包含特定文本。并且一旦设置会影响所有的find_element操作。建议可以设置一个较短的全局隐式等待如5秒作为基础保障但不要依赖它处理复杂场景。显式等待WebDriverWait(driver, timeout).until(condition)是什么针对某个特定条件进行等待条件满足则立即继续执行超时则抛出异常。这是最推荐、最智能的等待方式。核心expected_conditions模块提供了大量预定义条件如presence_of_element_located元素出现在DOM中不一定可见、可点击。visibility_of_element_located元素可见宽高大于0。element_to_be_clickable元素可见且可点击。title_contains页面标题包含特定文字。优点精准、高效、灵活。针对不同操作使用不同的等待条件脚本健壮性大大提升。示例如上文代码中我们在点击搜索按钮前使用了element_to_be_clickable条件确保按钮确实可以点了才去点击。最佳实践显式等待为主隐式等待为辅强制等待慎用。通常我会在创建driver后设置一个较短的隐式等待如5秒作为兜底然后在所有关键操作前使用显式等待。5.3 高级操作处理弹窗、滚动与执行JS真实的网页往往更复杂。我们来看看如何处理一些常见场景。处理JavaScript弹窗Alert/Confirm/Promptfrom selenium.webdriver.common.alert import Alert # 假设某个操作会触发一个确认框 driver.find_element(By.ID, “trigger-alert”).click() # 切换到弹窗 alert Alert(driver) print(“弹窗文本”, alert.text) # 接受点击“确定” alert.accept() # 或者取消点击“取消” # alert.dismiss() # 如果是Prompt弹窗有输入框还可以输入文本 # alert.send_keys(“输入的内容”) # alert.accept()滚动页面有时需要操作的元素不在当前可视区域内需要滚动。from selenium.webdriver.common.action_chains import ActionChains # 方法1使用JavaScript直接滚动到元素 element driver.find_element(By.ID, “target-element”) driver.execute_script(“arguments[0].scrollIntoView(true);”, element) # true表示与窗口顶部对齐 time.sleep(1) # 等待滚动完成 # 方法2使用JavaScript滚动到指定位置 driver.execute_script(“window.scrollTo(0, document.body.scrollHeight);”) # 滚动到底部 driver.execute_script(“window.scrollTo(0, 500);”) # 滚动到纵坐标500像素 # 方法3使用ActionChains模拟鼠标滚轮更贴近用户操作但可能不兼容所有浏览器 actions ActionChains(driver) actions.move_to_element(element).perform()执行任意JavaScript代码execute_script是Selenium的一把瑞士军刀可以突破WebDriver API的限制。# 修改元素属性 driver.execute_script(“document.getElementById(‘kw’).value ‘Selenium’;”) # 获取元素样式 bg_color driver.execute_script(“return window.getComputedStyle(document.body).backgroundColor;”) # 处理复杂的鼠标事件或DOM操作 # ...6. 框架雏形让脚本更健壮、可维护一个直接写在main函数里的脚本是脆弱的。随着测试用例增多我们需要引入一些设计模式让代码结构清晰、易于维护和扩展。6.1 使用Page Object Model设计模式POM是目前最主流的自动化测试设计模式。其核心思想是将页面抽象成类将页面元素抽象成类的属性将页面操作抽象成类的方法。这样测试脚本业务逻辑就和页面细节定位器分离开了。以百度首页和搜索结果页为例pages/base_page.py(基础页面类)from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC class BasePage: def __init__(self, driver): self.driver driver self.wait WebDriverWait(driver, 10) def find_element(self, by, locator): 查找单个元素加入显式等待 return self.wait.until(EC.presence_of_element_located((by, locator))) def find_elements(self, by, locator): 查找多个元素 self.wait.until(EC.presence_of_element_located((by, locator))) return self.driver.find_elements(by, locator) def click(self, by, locator): 点击元素确保可点击 element self.wait.until(EC.element_to_be_clickable((by, locator))) element.click()pages/baidu_home_page.py(百度首页)from selenium.webdriver.common.by import By from pages.base_page import BasePage class BaiduHomePage(BasePage): # 页面元素定位器 SEARCH_INPUT (By.ID, “kw”) SEARCH_BUTTON (By.ID, “su”) def __init__(self, driver): super().__init__(driver) self.driver.get(“https://www.baidu.com”) def search_for(self, keyword): 在搜索框输入关键词并点击搜索 self.find_element(*self.SEARCH_INPUT).clear() self.find_element(*self.SEARCH_INPUT).send_keys(keyword) self.click(*self.SEARCH_BUTTON) # 返回搜索结果页对象实现页面跳转的链式调用 return BaiduSearchResultPage(self.driver)pages/baidu_search_result_page.py(百度搜索结果页)from selenium.webdriver.common.by import By from pages.base_page import BasePage class BaiduSearchResultPage(BasePage): # 搜索结果标题元素 RESULT_TITLES (By.CSS_SELECTOR, “h3.t”) def get_all_result_titles(self): 获取所有搜索结果的标题文本 title_elements self.find_elements(*self.RESULT_TITLES) return [title.text for title in title_elements] def get_all_result_links(self): 获取所有搜索结果的链接 title_elements self.find_elements(*self.RESULT_TITLES) links [] for title in title_elements: link title.find_element(By.XPATH, “./parent::a”).get_attribute(“href”) links.append(link) return linkstests/test_baidu_search.py(测试脚本)import pytest from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager from pages.baidu_home_page import BaiduHomePage class TestBaiduSearch: def setup_method(self): 每个测试方法开始前执行 service Service(ChromeDriverManager().install()) self.driver webdriver.Chrome(serviceservice) self.driver.maximize_window() def teardown_method(self): 每个测试方法结束后执行 self.driver.quit() def test_search_automation(self): 测试百度搜索‘自动化测试’ home_page BaiduHomePage(self.driver) # 链式调用从首页搜索直接进入结果页 result_page home_page.search_for(“自动化测试”) titles result_page.get_all_result_titles() links result_page.get_all_result_links() assert len(titles) 0, “未找到任何搜索结果” print(f“搜索到 {len(titles)} 条结果。”) # 可以添加更具体的断言比如检查标题中是否包含关键词 assert any(“自动化” in title for title in titles), “搜索结果中未包含预期关键词” if __name__ “__main__”: # 简单运行 test TestBaiduSearch() test.setup_method() test.test_search_automation() test.teardown_method()POM的优势高可维护性页面元素定位器集中管理前端页面改版时只需修改对应的Page Class测试脚本几乎不用动。高可读性测试脚本读起来就像自然语言home_page.search_for(“xxx”)业务逻辑清晰。低冗余公共操作如等待、查找封装在基类中避免代码重复。6.2 数据驱动测试将测试数据如搜索关键词、断言期望值从脚本中分离出来存放在外部文件如JSON, CSV, Excel或代码中使一套脚本可以执行多组数据测试。简单示例使用Python列表import pytest # 测试数据 search_data [ (“自动化测试”, True), # 关键词 期望找到结果 (“Selenium”, True), (“一个不存在的稀奇古怪关键词xyz”, False), # 期望没有结果 (“”, False), # 空搜索 ] pytest.mark.parametrize(“keyword, expected_to_have_results”, search_data) def test_search_with_different_keywords(keyword, expected_to_have_results): # ... 初始化driver和page ... home_page BaiduHomePage(driver) result_page home_page.search_for(keyword) titles result_page.get_all_result_titles() if expected_to_have_results: assert len(titles) 0, f“搜索‘{keyword}’时期望有结果但实际没有。” # 可以进一步断言标题相关性 else: # 对于无结果或空搜索百度可能展示提示信息或无结果页这里简化处理 # 实际应根据页面具体行为断言 print(f“关键词 ‘{keyword}’ 的搜索结果数量为{len(titles)}”)7. 常见问题排查与实战技巧即使按照最佳实践编写脚本在实际运行中还是会遇到各种问题。这里分享一些高频问题的排查思路和技巧。7.1 元素定位失败NoSuchElementException这是最常见的问题。排查步骤检查定位器首先确认你的定位器XPath/CSS是否正确。在浏览器开发者工具的Console中可以用$$(“你的CSS”)或$x(“你的XPath”)快速测试是否能找到元素。检查等待元素还没加载出来你就去找它了。增加显式等待并选择合适的等待条件如visibility_of_element_located。检查iframe/Shadow DOM如果元素在iframe或Shadow DOM内部你需要先切换到对应的上下文。切换iframeiframe driver.find_element(By.TAG_NAME, “iframe”) driver.switch_to.frame(iframe) # 在iframe内操作元素 # ... driver.switch_to.default_content() # 操作完切回主文档处理Shadow DOM需要使用JavaScript来穿透。shadow_host driver.find_element(By.CSS_SELECTOR, “#shadow-host”) shadow_root driver.execute_script(“return arguments[0].shadowRoot”, shadow_host) inner_element shadow_root.find_element(By.CSS_SELECTOR, “.inner-element”)检查页面是否发生跳转或刷新页面跳转后之前的元素引用会失效。需要在操作前重新定位。检查浏览器窗口大小某些响应式页面元素在小窗口下可能被隐藏或布局改变。尝试driver.maximize_window()。7.2 脚本运行不稳定有时成功有时失败这通常是竞态条件导致的即脚本执行速度与页面响应速度不匹配。根治方法用显式等待替代所有固定的sleep。确保每个依赖页面状态的操作之前都等待其前置条件满足。重试机制对于某些特别不稳定的操作如网络请求可以引入简单的重试逻辑。from selenium.common.exceptions import StaleElementReferenceException import time def click_with_retry(element_locator, retries3): for attempt in range(retries): try: element wait.until(EC.element_to_be_clickable(element_locator)) element.click() return True except StaleElementReferenceException: # 元素引用失效可能是DOM更新了等待一下再试 if attempt retries - 1: time.sleep(0.5) else: raise7.3 浏览器行为与预期不符弹窗拦截有些操作如下载、新窗口打开可能会被浏览器拦截。需要提前更改浏览器选项。from selenium.webdriver.chrome.options import Options chrome_options Options() prefs { “download.default_directory”: “/path/to/download”, # 设置下载路径 “download.prompt_for_download”: False, # 禁止下载提示 “profile.default_content_setting_values.automatic_downloads”: 1 # 允许多文件下载 } chrome_options.add_experimental_option(“prefs”, prefs) driver webdriver.Chrome(optionschrome_options)证书错误/不安全提示访问HTTPS站点遇到证书问题时。chrome_options Options() chrome_options.add_argument(‘--ignore-certificate-errors’) chrome_options.add_argument(‘--allow-insecure-localhost’) # 允许本地不安全连接浏览器通知禁用通知。chrome_options.add_experimental_option(“prefs”, { “profile.default_content_setting_values.notifications”: 2 # 2代表阻止 })7.4 提升脚本执行速度与资源管理使用无头模式不需要看到浏览器UI时使用无头模式可以大幅节省资源特别适合CI/CD环境。chrome_options Options() chrome_options.add_argument(“--headless”) # 启用无头模式 chrome_options.add_argument(“--disable-gpu”) # Windows系统可能需要 chrome_options.add_argument(“--no-sandbox”) # Linux系统有时需要 chrome_options.add_argument(“--disable-dev-shm-usage”) # 解决共享内存问题及时清理确保在finally块或测试框架的teardown方法中调用driver.quit()防止残留进程。复用浏览器会话对于需要登录的复杂测试可以考虑复用用户数据目录避免每次重新登录。chrome_options.add_argument(f”user-data-dir{os.path.expanduser(‘~’)}/chrome_test_profile”)8. 从脚本到测试集成与报告单个脚本跑通只是开始我们需要将其纳入到完整的测试流程中并生成清晰的测试报告。8.1 使用Pytest测试框架Pytest比Python自带的unittest更简洁强大。安装pip install pytest。组织测试用例按照POM模式将测试脚本放在tests目录下文件名以test_开头函数名也以test_开头。使用Fixture管理驱动生命周期Pytest的fixture可以优雅地实现setup和teardown。# conftest.py (放在项目根目录或tests目录下) import pytest from selenium import webdriver from selenium.webdriver.chrome.service import Service from webdriver_manager.chrome import ChromeDriverManager pytest.fixture(scope“function”) # 每个测试函数执行一次 def driver(): service Service(ChromeDriverManager().install()) _driver webdriver.Chrome(serviceservice) _driver.maximize_window() yield _driver # 测试函数执行时传入_driver _driver.quit() # 测试函数执行完后执行quit # test_baidu.py def test_search(driver): # driver fixture会自动注入 home_page BaiduHomePage(driver) result_page home_page.search_for(“pytest”) assert len(result_page.get_all_result_titles()) 0运行测试在项目根目录下执行pytest命令即可自动发现并运行所有测试。可以加参数如pytest -v详细输出、pytest --htmlreport.html生成HTML报告需安装pytest-html。8.2 生成美观的测试报告清晰的报告能直观反映测试结果。除了pytest-htmlAllure是更专业的选择。安装Allure需要先安装Java然后从 Allure官网 下载命令行工具并配置PATH。安装Pytest的Allure适配器pip install allure-pytest。运行测试并生成报告pytest --alluredir./allure-results # 运行测试生成原始数据 allure serve ./allure-results # 在本地启动服务查看报告 # 或生成静态HTML报告 allure generate ./allure-results -o ./allure-report --cleanAllure报告会展示测试用例的通过率、失败原因、执行步骤、甚至截图非常利于问题定位。8.3 集成到CI/CD流水线自动化测试的价值在CI/CD中才能最大化体现。以GitHub Actions为例可以创建一个工作流文件.github/workflows/test.ymlname: Web Automation Tests on: [push, pull_request] # 在代码推送或PR时触发 jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkoutv2 - name: Set up Python uses: actions/setup-pythonv2 with: python-version: ‘3.9’ - name: Install dependencies run: | pip install -r requirements.txt pip install pytest allure-pytest - name: Install Chrome and ChromeDriver run: | sudo apt-get update sudo apt-get install -y wget wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add - echo “deb [archamd64] http://dl.google.com/linux/chrome/deb/ stable main” | sudo tee /etc/apt/sources.list.d/google-chrome.list sudo apt-get update sudo apt-get install -y google-chrome-stable # 使用webdriver-manager无需单独安装ChromeDriver - name: Run tests with Allure run: | pytest --alluredirallure-results - name: Upload Allure report uses: actions/upload-artifactv2 if: always() # 即使测试失败也上传报告 with: name: allure-report path: allure-results/这样每次代码提交都会自动运行你的Web自动化测试并将结果报告保存下来团队任何成员都可以查看实现了质量的持续反馈。从打开一个浏览器到定位一个元素再到构建一个健壮的POM框架最后集成到CI/CD流水线中生成专业报告这就是一个完整的Web自动化测试从入门到实战的路径。这条路没有捷径最大的技巧就是“动手写动手调多思考”。当你成功地将第一个自动化脚本融入团队的工作流并看着它每天自动守护着产品的质量时你会觉得这一切的投入都是值得的。自动化测试不是银弹它无法替代探索性测试和人的智慧但它是最可靠的守夜人能把你从重复的劳动中解放出来去解决更复杂、更有趣的问题。