基于 Selenium+Page Object 的电商平台自动化测试框架实践
引言:为什么需要电商自动化测试框架?
在电商平台测试中,用户登录、个人信息管理、商品浏览、购物车结算等核心流程需反复验证,手动测试不仅效率低下(重复操作占比超 60%),还易因疲劳导致漏测、误判。而基于 Selenium 的自动化测试框架,能将这些流程固化为可复用脚本,实现 “一次编写,多次执行”,同时提升测试结果的稳定性与可追溯性。
本文将结合实际代码,详解如何用Page Object 模式设计电商自动化测试框架,覆盖 “用户认证 - 个人中心 - 商品购物” 全流程,解决元素定位不稳定、代码冗余、流程串联难等常见问题。
测试用例
一、技术选型:工具与核心优势
框架基于 Python 生态构建,选择的工具均围绕 “稳定性、可维护性” 设计,具体选型如下:
技术 / 工具 | 核心用途 | 选择理由 |
---|---|---|
Python 3.10 | 框架开发核心语言 | 语法简洁、测试库丰富(Selenium/Pytest) |
Selenium WebDriver | 模拟浏览器操作 | 支持 Chrome/Edge 等多浏览器,跨平台 |
WebDriverWait+EC | 显式等待机制 | 解决页面加载延迟导致的元素定位失败(比 sleep 更灵活) |
Page Object 模式 | 页面元素与操作封装 | 降低耦合度,页面变更时仅需修改对应类 |
截图日志 | 故障排查 | 元素定位失败时自动保存截图,快速定位问题 |
二、框架整体设计:模块划分与类关系
框架按 “用户操作流程” 将页面拆分为 3 大核心模块,共 10 个页面类,类之间通过 “页面跳转方法” 串联,形成完整测试链路。
模块划分示意图
用户认证模块 → 个人中心模块 → 商品购物模块
├─ LoginPage(账号密码登录) ├─ PersonalPage(个人中心首页) ├─ ShopPage(商城首页)
├─ MBLoginPage(手机验证码登录)├─ PersonalDataPage(个人资料) ├─ CartConfirm(加购确认)
└─ RegisterPage(注册) ├─ EditPage(资料编辑) ├─ ShopCartCheckOutPage(购物车结算)├─ AddressPage(地址管理) └─ SettleMent(订单提交)└─ UpLoadPage(头像上传)
- 每个页面(如登录页、商品页)对应一个 Page 类,封装该页面的元素定位与操作方法(如 “输入账号”“点击登录”)。
- 页面类的方法返回下一个页面的实例(如
LoginPage.click_login()
返回PersonalPage
),实现 “登录→进入个人中心” 的自然流转。 - 所有元素定位均用
WebDriverWait+EC
(而非time.sleep
),确保元素加载完成后再操作,提升稳定性。
三、核心模块
下面按 “用户认证→个人中心→商品购物” 顺序,解析关键页面类的设计思路与核心方法。
模块 1:用户认证(LoginPage 为例)
用户认证是所有流程的前置步骤,LoginPage
需支持 “账号密码登录”“切换手机验证码登录”“跳转注册页” 三大功能,同时处理 “验证码定位失败”“登录按钮不可点击” 等异常场景。
关键代码与设计亮点
class LoginPage(BasePage):def __init__(self, driver):super().__init__(driver)# 元素定位:用元组存储(定位方式,定位表达式),避免硬编码扩散self.url = "http://8.155.1.153/?s=user/loginInfo.html"self.username_locators = (By.CSS_SELECTOR, "input[type='text']") # 账号输入框self.password_locators = (By.CSS_SELECTOR, "input[type='password']") # 密码输入框self.login_btn = (By.XPATH, "/html/body/div[1]/div[1]/div[3]/div/div[2]/div[2]/div[2]/div/div[1]/div[1]/form/div[4]") # 登录按钮def open_Login_Url(self):"""打开登录页并等待页面加载完成"""self.driver.get(self.url)# 等待页面完全加载(document.readyState == "complete")WebDriverWait(self.driver, 15).until(lambda driver: driver.execute_script("return document.readyState") == "complete")self.driver.save_screenshot("page_loaded.png") # 保存加载截图,便于排查return selfdef click_login(self):"""点击登录,跳转至个人中心"""# 延迟导入:解决LoginPage与PersonalPage循环依赖问题from .PersonalPage import PersonalPagetry:# 显式等待登录按钮可点击login_btn = WebDriverWait(self.driver, 3).until(EC.element_to_be_clickable(self.login_btn))login_btn.click()return PersonalPage(self.driver) # 返回下一页实例,实现流程串联except TimeoutException:self.driver.save_screenshot("login_btn_timeout.png")print("登录按钮等待超时")raise # 抛出异常,便于测试用例捕获
这里加入了等待与抛异常,假设按钮点击失败、或者按钮未出现,此时就抛出异常,并打印错误信息
模块 2:个人中心(PersonalDataPage 为例)
个人中心模块负责 “查看 / 编辑个人信息、修改手机号、上传头像” 等操作,PersonalDataPage
需提供 “数据读取”(如获取用户名、手机号)与 “页面跳转”(如进入编辑页)方法。
class PersonalDataPage(BasePage):def __init__(self, driver):super().__init__(driver)self.name = (By.XPATH, "/html/body/div[1]/div[1]/div[3]/div[3]/div/dl/dd[2]") # 用户名元素self.edit = (By.CSS_SELECTOR, "a.am-text-sm.am-color-main") # 编辑按钮def get_name(self):"""获取当前用户名,用于断言验证"""name_elem = WebDriverWait(self.driver, 3).until(EC.presence_of_element_located(self.name))return name_elem.text # 返回文本,供测试用例断言(如“是否与输入的用户名一致”)def goto_编辑页_by_click_编辑(self):"""点击编辑按钮,进入资料编辑页"""edit_btn = self.driver.find_element(*self.edit)if edit_btn:edit_btn.click()print("已进入编辑页")return EditPage(self.driver) # 跳转至EditPageraise NoSuchElementException("编辑按钮未找到")
数据读取与断言:get_name()
等方法返回页面数据,测试用例可通过assert personal_data_page.get_name() == "测试用户"
验证信息是否正确。
单一职责:PersonalDataPage
仅负责 “个人资料页” 的操作,编辑逻辑交给EditPage
,符合 “单一职责原则”,代码更易维护。
模块 3:商品购物(ShopPage 为例)
商品购物模块是电商测试的核心,ShopPage
需支持 “商品分类浏览、商品详情跳转、加入购物车” 等操作,其中 “多窗口切换”(点击商品打开新窗口)是常见难点。
关键方法:商品详情页跳转
class ShopPage(BasePage):def goto_商品详情页_by_click_商品(self, index: int):"""点击第index个商品,跳转至详情页(处理多窗口切换):param index: 商品索引(从0开始)"""# 1. 等待商品列表加载product_list = WebDriverWait(self.driver, 5).until(EC.presence_of_element_located((By.CLASS_NAME, "am-avg-sm-2")))items = product_list.find_elements(By.TAG_NAME, "li")print(f"共找到{len(items)}个商品")# 2. 记录当前窗口句柄(用于后续切换)main_window = self.driver.current_window_handle# 3. 点击商品(打开新窗口)target_item = items[index]target_item.find_element(By.CSS_SELECTOR, "a.am-block.goods-info").click()# 4. 等待新窗口打开并切换WebDriverWait(self.driver, 10).until(EC.number_of_windows_to_be(2)) # 等待窗口数变为2new_window = [w for w in self.driver.window_handles if w != main_window][0]self.driver.switch_to.window(new_window) # 切换到新窗口# 5. 等待详情页加载完成WebDriverWait(self.driver, 10).until(lambda driver: driver.execute_script("return document.readyState") == "complete")return self
难点解决:多窗口切换
- 记录原窗口:点击商品前用
main_window = self.driver.current_window_handle
记录原窗口句柄。 - 等待新窗口:用
EC.number_of_windows_to_be(2)
确保新窗口已打开,避免切换过早导致失败。 - 切换窗口:通过列表推导式
[w for w in self.driver.window_handles if w != main_window][0]
找到新窗口句柄,再用switch_to.window()
切换。
四、完整测试流程实战
下面以 “用户登录→编辑个人资料→添加商品到购物车” 为例,展示如何串联各页面类,实现端到端自动化测试。
测试脚本示例
from selenium import webdriver
from pages.LoginPage import LoginPage
from pages.PersonalDataPage import PersonalDataPage
from pages.EditPage import EditPage
from pages.ShopPage import ShopPagedef test_edit_profile_and_add_to_cart():# 1. 初始化浏览器driver = webdriver.Chrome()driver.maximize_window()try:# 2. 登录流程:打开登录页→输入账号密码→点击登录login_page = LoginPage(driver)personal_page = login_page.open_Login_Url() \.find_username().send_keys("test_user") \.find_password().send_keys("test_password") \.click_login()# 3. 编辑个人资料:进入个人资料页→点击编辑→输入姓名→选择性别→保存personal_data_page = personal_page.goto_个人资料页_by_click_修改资料()edit_page = personal_data_page.goto_编辑页_by_click_编辑()edit_page.find_name().send_keys("新测试用户") \.click_man() # 选择男性.click_保存()# 4. 验证资料修改:返回个人资料页,断言姓名是否正确updated_name = personal_data_page.get_name()assert updated_name == "新测试用户", f"资料修改失败,当前姓名:{updated_name}"# 5. 商品购物:跳转商城→点击商品→加入购物车shop_page = personal_page.goto_商城页_by_click_商城首页()shop_page.goto_商品详情页_by_click_商品(index=0) \.select_red_color() # 选择红色.click_Add_to_cart() # 加入购物车print("测试流程执行完成,所有步骤均通过!")finally:# 6. 关闭浏览器driver.quit()if __name__ == "__main__":test_edit_profile_and_add_to_cart()
脚本特点
- 链式调用:页面方法返回自身实例(如
edit_page.find_name().send_keys(...)
),代码更简洁。 - 断言验证:通过
assert updated_name == "新测试用户"
验证资料修改结果,确保功能正常。 - 资源释放:用
finally
确保浏览器无论是否报错都会关闭,避免资源泄漏。
五、现存问题与优化建议
当前框架已能满足基础电商测试需求,但仍有可优化空间,以下是关键改进方向:
1. 元素定位优化:避免绝对 XPATH
问题:代码中大量使用绝对 XPATH(如/html/body/div[1]/div[1]/div[3]/div[3]/div/form/div[1]/div[1]/input
),页面结构变更时(如新增一个 div),XPATH 会失效。
优化方案:改用相对 XPATH 或 CSS_SELECTOR,基于元素属性定位:
# 优化前:绝对XPATH
self.name = (By.XPATH, "/html/body/div[1]/div[1]/div[3]/div[3]/div/form/div[1]/div[1]/input")
# 优化后:相对XPATH(基于name属性)
self.name = (By.XPATH, "//form//input[@name='username']")
# 或CSS_SELECTOR(基于class)
self.name = (By.CSS_SELECTOR, "form .user-name-input")
2. 异常处理优化:统一封装 BasePage
问题:各页面类的异常处理重复(如每个方法都写try-except+截图
)。
优化方案:在BasePage
中封装通用元素定位方法,统一处理异常:
class BasePage:def __init__(self, driver):self.driver = driverdef find_element(self, locator):"""通用元素定位方法,统一处理异常"""try:return WebDriverWait(self.driver, 5).until(EC.presence_of_element_located(locator))except TimeoutException:self.driver.save_screenshot(f"element_timeout_{locator[0]}.png")raise Exception(f"元素定位超时:{locator}")# 子页面类调用
class EditPage(BasePage):def find_name(self):input = self.find_element(self.name) # 直接调用BasePage的方法print("输入框已找到")return self
六、总结与
本文基于 Page Object 模式,设计了覆盖电商 “用户认证 - 个人中心 - 商品购物” 全流程的自动化测试框架,核心优势在于:
- 页面变更仅需修改对应 Page 类,测试用例无需改动。
- 页面方法可在多个测试场景中复用(如
click_Add_to_cart()
可用于 “加购单个商品”“加购多个商品”)。 - 代码结构清晰,新人可快速上手(通过方法名即可理解操作意图)。
后续可进一步扩展的功能:
1.集成 Pytest:实现测试用例批量执行、测试报告生成(如 Allure 报告)。
2.加入数据驱动:用不同测试数据(如正确账号、错误密码)自动生成多组测试用例。
3.集成 CI/CD:通过 Jenkins 实现 “代码提交后自动执行测试”,实现持续测试。