You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Selenium POM模式下driver对象传递及属性报错解决方案

问题根因

这个报错和driver传递逻辑无关,核心是两个Python语法+POM实现逻辑的问题:

  • 类实例属性定义错误:你在LoginPage的__init__构造方法里定义emailField/passwordField/loginButton时没有加self.前缀,这三个变量只是构造方法内的局部变量,实例化后的LoginPage对象根本访问不到,直接触发AttributeError。
  • 元素查找时机错误:你在构造方法里就执行DOM元素查找,实例化页面对象的瞬间就会去页面找元素,既容易因为页面未加载完成触发找不到元素的异常,后续页面刷新、跳转后这些提前缓存的元素引用还会触发陈旧元素引用(stale element reference)报错。
  • 额外注意:你代码里用的find_element_by_css_selector/find_element_by_id系列方法在Selenium 4版本已经被完全移除,运行时会抛废弃警告甚至直接报错,需要替换为find_element(By.XXX, 定位表达式)的标准写法。
修复步骤
  1. 调整LoginPage类实现,不要在构造方法里直接查找元素,优先存储元素定位器,通过懒加载的方式在真正使用元素时再执行查找:
from selenium.webdriver.common.by import By
from pages.basepage import BasePage

class LoginPage(BasePage):
    # 统一维护元素定位器,后续修改定位规则只需要改这一处
    _email_field_locator = (By.CSS_SELECTOR, 'input[name="username"]')
    _password_field_locator = (By.CSS_SELECTOR, 'input[name="password"]')
    _login_button_locator = (By.CSS_SELECTOR, 'input[type="submit"]')

    def __init__(self, driver):
        super().__init__(driver)
        self.driver = driver

    # 用@property装饰器实现懒加载,访问属性时才实时查找DOM元素
    @property
    def emailField(self):
        return self.driver.find_element(*self._email_field_locator)
    
    @property
    def passwordField(self):
        return self.driver.find_element(*self._password_field_locator)
    
    @property
    def loginButton(self):
        return self.driver.find_element(*self._login_button_locator)
  1. 调整测试代码里的废弃API写法,建议补充显式等待避免页面加载时序问题:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
from pages.adminpage import AdminPage
from pages.loginpage import LoginPage

driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('http://localhost:8000/admin/')
driver.maximize_window()

loginPage = LoginPage(driver)

# 等待邮箱输入框加载完成后再做焦点校验
wait = WebDriverWait(driver, 10)
wait.until(EC.element_to_be_clickable(loginPage._email_field_locator))
assert driver.switch_to.active_element == loginPage.emailField
# 替换废弃的find_element_by_id写法
driver.find_element(By.ID, 'djHideToolBarButton').click()

loginPage.emailField.send_keys("admin@admin.com")
loginPage.passwordField.send_keys("admin")
loginPage.loginButton.click()

adminPage = AdminPage(driver)
adminPage.checkTabOrder()

driver.quit()

你之前写的driver传递逻辑是完全正确的,不需要调整这部分逻辑。

内容的提问来源于stack exchange,提问作者Keiggo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 17:01:27