Selenium自动化测试入门:从登录到列表页断言的核心方法与实战
·
一、前言
自动化测试的第一步往往是登录,然后进入列表页验证数据。这两个板块看似简单,但涉及元素定位、隐式等待与显式等待、浏览器弹窗(alert)、列表长度断言等常见场景。本文结合我的博客系统测试代码,按照“登录成功 → 登录失败 → 进入列表页 → 断言文章数量”的顺序,记录核心方法和踩坑经验。## 二、核心方法速查表
| 功能 | 方法 | 说明 |
|---|---|---|
| 定位单个元素 | driver.find_element(By.CSS_SELECTOR, "...") | 找不到抛异常 |
| 定位多个元素 | driver.find_elements(...) | 返回列表,可 len() |
| 输入文本 | element.send_keys("文本") | 仅对 input/textarea 有效 |
| 点击 | element.click() | 需元素可交互 |
| 强制等待 | time.sleep(秒) | 简单但效率低 |
| 隐式等待 | driver.implicitly_wait(秒) | 全局查找元素超时,不影响 .text 或弹窗 |
| 显式等待 | WebDriverWait(driver, 秒).until(条件) | 灵活推荐,可等元素出现、弹窗等 |
| 弹窗切换 | driver.switch_to.alert | 需先等弹窗出现 |
| 获取当前标题 | driver.title | 常用于断言页面跳转 |
三、创建公共驱动
这里采用单例模式,提前创建好公共驱动,这样每次测试功能前就不用重复创建了。
class Driver:
driver = None
def __init__(self):
if Driver.driver is None:
options = Options()
options.binary_location = r"D:\Program Files\Google\Chrome\Application\chrome.exe"
Driver.driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
self.driver = Driver.driver # 让实例也有 driver 属性
def getScreenShot(self):
filename = "autotest-" + datetime.datetime.now().strftime('%Y-%m-%d-%H%M%S') + '.png'
self.driver.save_screenshot('../test02/images/' + filename)
DriverTest = Driver()
四、板块1:登录测试(BlogLogin.py)
4.1 登录成功测试
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from common.Utils import DriverTest
class BlogLogin:
url = ""
driver = ""
def __init__(self):
self.driver = DriverTest.driver
print("login")
print(self.driver)
self.url = "url"
self.driver.get(self.url)
def backLogin(self):
self.driver.back()
def login(self):
time.sleep(2)
self.driver.find_element(By.CSS_SELECTOR, "#username").send_keys("zhangsan")
self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("123456")
self.driver.find_element(By.CSS_SELECTOR, "#submit").click()
time.sleep(2)
text = self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.left > div > h3").text
print(text)
assert text == "zhangsan"
if text == "zhangsan":
print("登录成功")
DriverTest.getScreenShot()
def clearInput(self):
self.driver.find_element(By.CSS_SELECTOR, "#username").clear()
self.driver.find_element(By.CSS_SELECTOR, "#password").clear()
def loginFailTest(self):
time.sleep(2)
self.driver.find_element(By.CSS_SELECTOR, "#username").send_keys("zhangsan")
self.driver.find_element(By.CSS_SELECTOR, "#password").send_keys("1234567")
self.driver.find_element(By.CSS_SELECTOR, "#submit").click()
print("弹窗测试开始")
# 显式等待弹窗出现(最多等待 5 秒)
WebDriverWait(self.driver, 5).until(EC.alert_is_present())
alert = self.driver.switch_to.alert
text = alert.text
if text == "用户不存在":
print("用户不存在,登录失败")
if text == "密码错误":
print("密码错误,登录失败")
alert.accept()
DriverTest.getScreenShot()
self.driver.back()
4.2 登录测试运行代码
def run_tests():
# 创建 BlogLogin 实例(此时会自动打开登录页面)
blog_login = BlogLogin()
# 1. 登录成功测试
print("========== 登录成功测试 ==========")
blog_login.login()
blog_login.backLogin()
blog_login.clearInput()
# 注意:login() 方法最后执行了 self.driver.back(),返回了登录页
# 但为了保险,可以加一点等待
time.sleep(2)
# 2. 登录失败测试(密码错误,预期弹窗“密码错误”)
print("========== 登录失败测试(密码错误) ==========")
blog_login.loginFailTest()
# 所有测试完成后关闭浏览器
DriverTest.driver.quit()
登录测试

4.3 我遇到的错误
错误1:NoAlertPresentException – 弹窗未出现
- 现象:点击登录按钮后,执行
switch_to.alert立刻报错,提示没有弹窗。 - 原因:后端验证需要时间,弹窗还没弹出,代码就已经尝试切换。
- 解决方案:使用显式等待
WebDriverWait(driver, 5).until(EC.alert_is_present()),等弹窗出现后再切换。
错误2:UnexpectedAlertPresentException – 意外的弹窗仍存在
- 现象:已经在代码中调用了
alert.accept(),但后面执行find_element时,仍然报错说有未处理的弹窗。 - 原因:这是一个典型的时序失效问题。
accept()执行后,弹窗可能因为页面动画、后续 JavaScript 脚本而尚未完全关闭;或者页面刷新后再次弹出了新的确认框。代码执行速度太快,在弹窗真正消失前就去操作 DOM 元素,导致 Selenium 检测到弹窗还在。 - 解决方案:在
accept()之后,添加等待弹窗消失的逻辑。例如等待一个列表页的特征元素出现:
alert.accept()
WebDriverWait(driver, 5).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "div.right"))
)
这样既等待了弹窗关闭,也等待了页面跳转完成。
五、板块2:博客列表页测试(BlogList.py)
5.1 进入列表页并断言文章数量
import time
from selenium.webdriver.common.by import By
from common.Utils import DriverTest
class BlogList:
driver = ""
def __init__(self):
self.driver = DriverTest.driver
print("List")
print(self.driver)
def ListTest(self):
print("select body")
time.sleep(2)
# html = self.driver.page_source
# print(html)
# print(self.driver.current_url)
articles = self.driver.find_elements(By.CSS_SELECTOR, "body > div.container > div.right > div")
print(articles)
assert len(articles) > 10
self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.right > div:nth-child(121)").click()
DriverTest.getScreenShot()
title = self.driver.title
assert title == "博客列表页"
DriverTest.getScreenShot()
5.2 我遇到的错误
错误1:TypeError: object of type ‘WebElement’ has no len()
- 现象:代码
articles = driver.find_element(...); assert len(articles) > 10报错,提示 WebElement 没有len()。 - 原因:使用了
find_element(单数),返回的是单个元素对象,而不是列表。 - 解决方案:改用
find_elements(复数)获取元素列表,再取长度。
错误2:NoSuchElementException – 点击第 121 篇文章时找不到元素
- 现象:
driver.find_element(By.CSS_SELECTOR, "...:nth-child(121)").click()抛出元素不存在异常。 - 原因:列表页实际文章数量不足 121 篇,或者页面结构发生变化。
- 解决方案:先获取文章总数,动态决定点击哪一篇:
articles = driver.find_elements(By.CSS_SELECTOR, "div.right > div")
assert len(articles) > 10
if len(articles) >= 121:
articles[120].click() # 索引从 0 开始
else:
articles[-1].click() # 点击最后一篇
错误3:断言 title == "博客列表页" 失败
- 现象:点击文章后,断言标题为“博客列表页”,但实际标题是“博客详情页”或其他。
- 原因:点击文章链接后页面跳转到了详情页,而不是停留在列表页。测试预期写错了。
- 解决方案:根据实际业务修改断言,例如
assert "详情" in driver.title或直接删除该断言。
错误4:页面跳转后元素找不到(NoSuchElementException)
- 现象:点击文章进入详情页后,后续代码仍用列表页的选择器找元素,报错找不到。
- 原因:没有等待新页面加载,也没有切换窗口句柄(如果新窗口打开)。
- 解决方案:点击后使用
WebDriverWait等待新页面的特征元素出现;如果新窗口打开,还需用driver.window_handles切换。
六、总结(第一篇)
- 登录模块核心:等待弹窗必须用显式等待。
- 列表页模块核心:用
find_elements获取列表长度,不要硬编码索引。
更多推荐
所有评论(0)