Python Selenium使用PageFactory编写POM测试报错解决方案
Selenium PageFactory 登录脚本报错排查与修复
问题根因汇总
你遇到的两个报错(递归深度溢出、super对象无__getattr__属性)都不是递归逻辑写法问题,也不是单纯元素加载慢导致的,核心是代码存在4个显性错误:
- 核心根因:子类构造方法未调用父类初始化方法。
SignInPage继承PageFactory后,重写的__init__方法仅赋值了self.driver,没有执行super().__init__(driver),父类构造方法中初始化的mobile_test、timeout等实例属性完全未创建。当PageFactory内置的__getattr__方法运行时,首先访问self.mobile_test,但该属性不存在就会再次触发__getattr__,形成无限递归,这就是RecursionError的来源,手动上调递归深度限制无法解决逻辑层面的死循环问题。 - 导入与类名、定位器键名不匹配:测试文件中导入的是
SignUpPage类,实际实例化时调用的是SignInPage,属于基础语法错误;同时堆栈日志显示代码中调用了self.user_name.set_text(),但locators字典中根本没有定义user_name这个定位键,访问不存在的定位器时,__getattr__方法走完locator匹配逻辑后会调用父类的__getattr__,但Python原生object类没有该方法,就会抛出AttributeError: 'super' object has no attribute '__getattr__'。 - 类名定位器写法错误:Selenium的
CLASS_NAME定位策略仅支持传入单个类名,你给登录按钮传入的class值包含空格(多个类名拼接),永远无法定位到元素。 - 输入操作多余的换行符:
set_text()方法本身会向输入框传入指定文本,你额外加\n可能触发非预期的提前表单提交逻辑。
修复后的代码
1. 页面对象文件(建议将sign_up_page.py重命名为sign_in_page.py,和类名保持一致)
from seleniumpagefactory.Pagefactory import PageFactory from selenium.webdriver.support.wait import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By class SignInPage(PageFactory): def __init__(self, driver): # 必须调用父类构造方法,可自定义显式等待超时时间 super().__init__(driver, timeout=15) self.driver = driver # 定位器写法修正:复合类名改用CSS选择器 locators = { "mail": ("ID", "userEmail"), "pwd": ("ID", "password"), "login_btn": ("CSS", "button.customStyle__ButtonDefault___1k2JQ.btn-primary") } def enter_username(self, username): # 等待元素可点击后再输入,替代硬等待 WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable((By.ID, "userEmail")) ) self.mail.set_text(username) def enter_password(self, password): WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable((By.ID, "password")) ) self.pwd.set_text(password) def click_login_btn(self): WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, "button.customStyle__ButtonDefault___1k2JQ.btn-primary")) ) self.login_btn.click_button()
2. 测试执行文件test_book.py
import sys import unittest from selenium import webdriver # 注意导入路径和类名匹配 from src.pages.sign_in_page import SignInPage class TestLogin(unittest.TestCase): def testLog(self): print(sys.getrecursionlimit()) driver = webdriver.Chrome() # 短时长隐式等待作为全局兜底 driver.implicitly_wait(5) driver.get("https://pubpp-developers.myriadgroup.mobi/login") # 删除无意义的time.sleep(10),用显式等待替代 user = SignInPage(driver) user.enter_username('address@gmail.com') user.enter_password('abcdef123') user.click_login_btn() # 测试完成后回收浏览器资源 driver.quit() if __name__ == "__main__": unittest.main()
页面元素未加载完成的标准处理方案
- 禁止滥用
time.sleep()硬等待:这种写法不管元素有没有加载完都会等固定时长,既拖慢测试执行效率,也会因为网络波动、页面渲染慢等场景出现等待时长不足的问题,稳定性极差。 - 优先用显式等待:针对每个操作的元素,明确指定等待条件(输入框、按钮等可交互元素用
EC.element_to_be_clickable,仅需判断元素存在用EC.presence_of_element_located,判断元素可见用EC.visibility_of_element_located),等待到条件满足立刻执行后续操作,超时没等到就抛出异常,稳定性和执行效率最优。 - 合理配置PageFactory内置超时:selenium-page-factory默认的元素等待超时是10秒,可以在调用父类构造方法时通过
timeout参数自定义全局等待时长,作为显式等待的兜底。 - 全局隐式等待作为补充:可以在driver初始化后设置一个短时长的隐式等待(3-5秒即可),定位元素时会自动轮询查找,但注意隐式等待无法判断元素是否可点击、可见,不能替代显式等待。
- 定位器优先用稳定属性:少用层级复杂的绝对XPATH、动态变化的随机class属性,优先用固定ID、name属性、自定义测试属性(比如
data-testid)定位元素,减少定位失败概率。
内容的提问来源于stack exchange,提问作者Aminata Willane
相关产品推荐
相关产品推荐

