一、Web自动化测试基础认知
1. 测试岗位体系与自动化价值
- 岗位层级:测试工程师(初/中/高)→ 测试组长(初/资深)→ 测试经理(初/资深)→ 交付部/事业部经理(战略决策)
- Web自动化ROI(投入产出比):
(手工执行成本×迭代次数) - 首次自动化成本 - (脚本维护×维护次数)
类比示例:功能测试=徒步找工作,Web自动化=先造车再开车找工作(长期迭代场景下自动化更高效)
2. Web自动化测试四个层次
层次 | 能力描述 | 核心目标 |
---|---|---|
小白阶段 | 掌握基础Python、元素定位、Selenium基础操作 | 实现简单线性脚本 |
轻量级POM封装 | 封装页面对象,调用PO属性/方法执行用例 | 解决代码复用与维护问题 |
关键字KDT封装 | 封装通用关键字,通过调用关键字执行用例 | 降低用例编写门槛 |
零代码极限封装 | 仅需编写Excel用例即可执行自动化 | 非技术人员可参与用例设计 |
二、环境搭建与基础脚本
1. 版本与安装
工具/框架 | 版本要求 | 安装命令/操作 |
---|---|---|
Selenium | 4.25(最新) | pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple/ |
Python | 3.11 | 安装时勾选“添加环境变量到Path” |
Pycharm | 最新 | 默认安装即可 |
谷歌浏览器 | 最新 | 默认安装 |
浏览器驱动 | 与浏览器版本匹配 | 复制到项目根目录 |
2. 基础脚本与关键配置
- 最小化脚本:启动浏览器、访问页面、停留后关闭
import time from selenium import webdriver driver = webdriver.Chrome() # 创建浏览器对象 driver.get("https://www.baidu.com") # 访问页面 time.sleep(5) # 停留5秒 driver.quit() # 关闭浏览器
- 浏览器不自动关闭:通过
ChromeOptions
配置options = webdriver.ChromeOptions() options.add_experimental_option("detach", True) # 禁止自动关闭 driver = webdriver.Chrome(options=options)
三、元素定位与实战操作
1. 定位核心逻辑
- 前提:元素属性唯一(确保定位准确性)
- Selenium八大定位方式:
ID(底层转CSS)、NAME(底层转CSS)、LINK_TEXT、PARTIAL_LINK_TEXT、XPATH、CSS_SELECTOR、TAG_NAME(几乎不用)、CLASS_NAME(底层转CSS) - 推荐定位方式:优先用XPATH(覆盖所有场景,语法灵活),其次用CSS_SELECTOR(语法复杂、不支持文本定位)
2. XPATH定位详解
定位类型 | 语法示例 | 说明 |
---|---|---|
绝对路径 | /html/body/form/table/tbody/tr/td[2]/input |
从根标签到目标标签,维护性差 |
相对路径+索引 | //input[2] |
定位页面中第2个input标签 |
相对路径+属性 | 单属性://input[@name="username"] ;多属性://input[@type="submit" and @value="进入管理中心"] |
通过标签属性定位,最常用 |
相对路径+部分属性 | //input[starts-with(@value,"进入")] (开头匹配);//input[contains(@value,"管理")] (包含匹配) |
适用于属性值动态变化场景 |
相对路径+文本 | //a[text()="商品列表"] |
匹配标签中间的完整文本(替代LINK_TEXT) |
相对路径+通配符 | //*[text()="商品列表"] ;//*[@type="submit"] |
* 匹配任意标签 |
3. 特殊场景处理
- 框架(frame/iframe):元素在框架内时需先切换
driver.switch_to.frame("menu-frame") # 进入框架(传frame的id/name) driver.switch_to.default_content() # 退出框架
- 下拉框(select):用
Select
类操作from selenium.webdriver.support.select import Select ele = driver.find_element(By.XPATH, "//select[@name='cat_id']") sel = Select(ele) sel.select_by_index(2) # 按索引(从0开始) sel.select_by_value("2") # 按option的value属性 sel.select_by_visible_text("手机类型") # 按option的可见文本
- 只读日历:通过JS移除
readonly
属性后操作ele = driver.find_element(By.XPATH, "//input[@name='promote_end_date']") driver.execute_script("arguments[0].removeAttribute('readonly');", ele) # 移除只读 ele.clear() ele.send_keys("2025-05-05")
- 文件上传:直接用
send_keys
传文件路径(仅适用于input[type="file"]
)driver.find_element(By.XPATH, "//input[@name='goods_img']").send_keys(r"D:\aaa.png")
- 定位一组元素:用
find_elements
获取列表,按索引操作ele_list = driver.find_elements(By.XPATH, "//img[@src='images/icon_trash.gif']") ele_list[0].click() # 点击第一个元素
- Alert弹窗:切换到弹窗后操作
ale = driver.switch_to.alert ale.accept() # 确认弹窗 # ale.dismiss() # 取消弹窗
四、测试框架核心(Pytest+Fixture+POM)
1. Pytest用例管理
- 用例发现规则:
模块名以test_
开头、类名以Test
开头、方法名以test_
开头 - 运行方式:
- 命令行:
pytest
(直接执行) - 主函数:
import pytest if __name__ == '__main__': pytest.main()
- 命令行:
- 全局配置文件(pytest.ini):放在项目根目录,自定义执行规则
[pytest] addopts = -vs -m smoke # 命令行参数(-vs显示详细日志,-m执行标记用例) testpaths = ./testcases # 用例文件夹 python_files = test_*.py # 用例模块名规则 python_classes = Test* # 用例类名规则 python_functions = test_* # 用例方法名规则 markers = smoke:冒烟测试 # 用例标记定义
- 核心插件:通过
requirements.txt
批量安装(如pytest-allure-adaptor
、pandas
等)
2. Conftest+Fixture实现前后置
- Conftest.py:
- 固定文件名,仅用于存放Fixture,无需导包即可调用
- 通常放在
testcases
目录下
- Fixture(固件/夹具):定义前后置操作,通过
scope
控制作用域import pytest from selenium import webdriver from selenium.webdriver.common.by import By # scope="function"(默认,每个方法前后),autouse=False(需手动调用) @pytest.fixture(scope="function", autouse=False) def all_case_fixture(): print("前置:打开浏览器并登录") driver = login_ecshop() # 自定义登录函数 yield driver # 分割前置与后置(yield后为后置) print("后置:关闭浏览器") # 登录函数(示例:登录ECShop后台) def login_ecshop(): options = webdriver.ChromeOptions() options.add_experimental_option("detach", True) driver = webdriver.Chrome(options=options) driver.get("http://192.168.0.44/ecshop/admin/privilege.php?act=logout") driver.find_element(By.XPATH, "//input[@name='username']").send_keys("admin") driver.find_element(By.XPATH, "//input[@name='password']").send_keys("admin123") driver.find_element(By.XPATH, "//input[@value='进入管理中心']").click() return driver
- Fixture作用域:
function
(方法)>class
(类)>module
(模块)>session
(项目)
3. POM(Page Object Model)设计模式
- 核心思想:将页面封装为“页面对象类”,用例层调用类的属性/方法,实现“数据-代码-页面”分离
- 三层结构:
层级 职责 示例代码片段 基础页面层(BasePage) 重写Selenium基础方法(如find_element、click),封装全局通用方法(如切换框架、截图) ```python class BasePage: def __init__(self, driver): self.driver = driver def find_ele(self, locator): return self.driver.find_element(*locator) def click_ele(self, locator): self.find_ele(locator).click()
| 页面对象层(PageObject) | 继承BasePage,定义当前页面的元素定位(属性)和业务操作(方法) | ```python class LoginPage(BasePage): # 元素定位(元组格式:(定位方式, 定位表达式)) username_loc = (By.XPATH, "//input[@name='username']") password_loc = (By.XPATH, "//input[@name='password']") login_btn_loc = (By.XPATH, "//input[@value='进入管理中心']") # 业务方法:登录操作 def login(self, username, password): self.find_ele(self.username_loc).send_keys(username) self.find_ele(self.password_loc).send_keys(password) self.click_ele(self.login_btn_loc) ```| | 测试用例层 | 创建页面对象实例,调用方法执行用例,传入测试数据 | ```python class TestLogin: def test_login_success(self, all_case_fixture): login_page = LoginPage(all_case_fixture) login_page.login("admin", "admin123") # 调用登录方法 ```|
- POM优势:降低代码冗余、提升维护效率(页面变更仅需修改页面对象类)
五、数据驱动与测试报告
1. 数据驱动(Parametrize+Excel)
核心工具:
@pytest.mark.parametrize
(Pytest内置)+pandas
(读取Excel)步骤1:准备Excel测试数据
示例表格(商品查询用例):index case_name type brand top supplier up search 1 根据分类查询商品 0 0 0 0 0 拜林 2 根据分类和品牌组合查询 5 1 0 0 0 翻1 步骤2:安装依赖库
pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple/ pip install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple/ # 读取Excel需此库
步骤3:读取Excel数据为字典列表
import pandas def read_excel_to_list(excel_path, sheet_name): # 读取Excel(engine='openpyxl'支持.xlsx格式) data = pandas.read_excel(excel_path, sheet_name=sheet_name, engine='openpyxl') # 转换为字典列表(每条用例为一个字典) dict_list = data.to_dict(orient='records') return dict_list # 测试:读取商品查询用例 if __name__ == '__main__': cases = read_excel_to_list(r"./testcases/sousuo_shop.xlsx", "select_shop") for case in cases: print(case) # 输出:{'index':1, 'case_name':'根据分类查询商品', ...}
步骤4:结合Pytest实现数据驱动
import pytest from pageobject.shop_page import ShopList # 导入页面对象 class TestShop: # 数据驱动:传入Excel读取的用例列表 @pytest.mark.parametrize("caseinfo", read_excel_to_list(r"./testcases/sousuo_shop.xlsx", "select_shop")) def test_select_shop(self, all_case_fixture, caseinfo): sl = ShopList(all_case_fixture) # 创建页面对象 sl.switch_to_frame() # 切换框架(页面方法) sl.select_by_value(str(caseinfo["type"])) # 按分类查询(传入Excel数据) sl.select_brand_by_value(str(caseinfo["brand"])) # 按品牌查询 sl.click_search() # 点击搜索
2. Pytest+Allure生成美观报告
步骤1:Allure安装与配置
- 下载:
https://pan.baidu.com/s/1pk3veMjY16YWpBvORwKGSg?pwd=snc6
- 解压:路径无中文(如
D:\allure-2.21.0
) - 配置环境变量:将
D:\allure-2.21.0\bin
加入系统PATH - 验证:命令行输入
allure --version
(重启Pycharm生效)
- 下载:
步骤2:生成临时JSON报告
修改pytest.ini
的addopts
:addopts = -vs --alluredir ./temps --clean-alluredir # ./temps存放临时报告,--clean清空旧报告
步骤3:生成HTML报告
在主函数中添加生成命令:import pytest import os import time if __name__ == '__main__': pytest.main() time.sleep(3) # 等待临时报告生成 # 生成HTML报告到./reports目录,--clean清空旧报告 os.system("allure generate ./temps -o ./reports --clean")
步骤4:报告定制(添加用例信息)
import allure # 项目级描述 @allure.epic("项目:Pytest+Selenium4 Web自动化测试框架训练营") class TestShop: @pytest.mark.parametrize("caseinfo", read_excel_to_list(r"./testcases/sousuo_shop.xlsx", "select_shop")) def test_select_shop(self, all_case_fixture, caseinfo): # 定制报告层级:模块→页面→用例名称 allure.dynamic.feature("模块:商品管理") allure.dynamic.story("页面:商品列表") allure.dynamic.title(f"用例:{caseinfo['case_name']}") # 用Excel的用例名 # 用例步骤(略,即页面对象方法调用) sl = ShopList(all_case_fixture) sl.switch_to_frame() sl.select_by_value(str(caseinfo["type"]))
六、企业级Web自动化落地技能栈
1. 核心技术栈
类别 | 技术/工具 | 说明 |
---|---|---|
编程语言 | Python/Java | 主流自动化开发语言(Python更简洁,适合快速落地) |
设计模式 | POM/关键字驱动/零代码封装 | POM用于中大型项目;关键字驱动降低门槛;零代码支持Excel用例 |
用例管理 | Pytest/unittest | Pytest功能更强(支持参数化、插件、灵活配置) |
分布式执行 | Selenium Grid | 多浏览器/多节点并行执行,提升用例执行效率 |
数据驱动 | Pytest Parametrize/DDT | Parametrize内置轻量;DDT支持Excel/CSV/YAML |
二次封装 | Selenium基础方法、数据库(MySQL)、配置文件 | 封装常用操作(如元素等待、截图),支持数据持久化 |
日志与异常 | 日志模块(logging)、异常捕获(try-except) | 记录用例执行过程,定位失败原因 |
持续集成 | Jenkins | 实现“代码提交→自动执行→报告生成”无人值守 |
容器化 | Docker | 统一测试环境,避免环境差异导致的用例失败 |
报告定制 | Allure | 支持自定义logo、用例层级、步骤详情 |
2. 企业落地分工示例
- 测试组长:框架设计、维护核心代码
- 测试工程师1:编写Excel用例(零代码场景)
- 测试工程师2:维护页面对象类、脚本调试
- 持续集成:Jenkins定时执行,失败邮件通知
3. 岗位能力与薪资
- 技能要求:Python+接口测试+Web自动化(15-30K);附加APP/性能测试(薪资上浮)
- 小公司:侧重工具使用(如Selenium基础脚本)
- 中公司:侧重自动化框架落地(POM、数据驱动)
- 大公司:侧重平台化建设(分布式、零代码、多端统一框架)