Selenium自动化脚本调试报错:hover元素失败,ClassCastException求助
Selenium登录自动化脚本ClassCastException问题排查
问题背景
我编写了一个基于Selenium的登录页自动化脚本,采用页面对象与方法类、可复用组件类、测试类的分离结构。运行脚本时抛出ClassCastException异常,调试模式下hover测试代码中的in_username对象时也会报错,尝试创建WebElement对象未解决问题,需协助排查。
代码结构
页面对象与方法类
public class LoginPage extends ReusableComponents { WebDriver driver; @FindBy(xpath="//input[@name='username']") public WebElement in_username; @FindBy(xpath="//input[@name='password']") WebElement in_password; @FindBy(xpath="//button[@type='submit']") WebElement btn_submit; public LoginPage(WebDriver driver) { super(driver); this.driver = driver; PageFactory.initElements(driver, this); } public void enterUname(String uname) { in_username.sendKeys(uname); } public void enterPassword(String pass) { in_password.sendKeys(pass); } public void clickSubmit() { btn_submit.click(); } }
可复用组件类
public class ReusableComponents { WebDriver driver; public ReusableComponents(WebDriver driver) { this.driver = driver; } public void setup() { WebDriverManager.chromedriver().setup(); driver = new ChromeDriver(); driver.manage().window().maximize(); driver.get("https://opensource-demo.orangehrmlive.com/web/index.php/auth/login"); } public void waitElementToAppear(WebElement findby){ WebDriverWait wait = new WebDriverWait(driver, 30); wait.until(ExpectedConditions.visibilityOfElementLocated((By) findby)); } public void closeBrowser() { driver.close(); } }
测试类
public class OpenBrowser { static WebDriver driver; public static void main(String[] args) { LoginPage login = new LoginPage(driver); ReusableComponents common = new ReusableComponents(driver); common.setup(); common.waitElementToAppear(login.in_username); login.enterUname("Admin"); login.enterPassword("admin123"); login.clickSubmit(); common.closeBrowser(); } }
错误日志
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Starting ChromeDriver 114.0.5735.90 (386bc09e8f4f2e025eddae123f36f6263096ae49-refs/branch-heads/5735@{#1052}) on port 31559 Only local connections are allowed. Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe. ChromeDriver was started successfully. Jun 29, 2023 8:43:53 AM org.openqa.selenium.remote.ProtocolHandshake createSession INFO: Detected dialect: W3C Exception in thread "main" java.lang.ClassCastException: class jdk.proxy2.$Proxy4 cannot be cast to class org.openqa.selenium.By (jdk.proxy2.$Proxy4 is in module jdk.proxy2 of loader 'app'; org.openqa.selenium.By is in the unnamed module of loader 'app') at com.orange.reusablecomponents.ReusableComponents.waitElementToAppear(ReusableComponents.java:32) at com.orangehrm.OpenBrowser.main(OpenBrowser.java:27)
错误截图

问题原因与修复方案
核心问题
- 类型转换错误:
waitElementToAppear方法接收WebElement参数,却强制将其转为By类型——两者是完全独立的类,无法直接转换,这是抛出ClassCastException的直接原因。 - driver初始化顺序错误:测试类中先创建
LoginPage实例,此时driver还是null,后续setup方法才初始化driver,导致LoginPage中的元素无法正确绑定到有效driver上。
修复步骤
1. 修正可复用组件类的等待方法
选择以下两种方案之一:
方案一:接收By类型定位器
public void waitElementToAppear(By locator){ // Selenium 4+推荐使用Duration设置超时 WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); wait.until(ExpectedConditions.visibilityOfElementLocated(locator)); }
对应页面对象类需要新增By类型的定位器:
public class LoginPage extends ReusableComponents { @FindBy(xpath="//input[@name='username']") public By usernameLocator; @FindBy(xpath="//input[@name='username']") public WebElement in_username; // 其余代码不变 }
测试类中调用方式改为:
common.waitElementToAppear(login.usernameLocator);
方案二:直接等待WebElement可见
public void waitElementToAppear(WebElement element){ WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); wait.until(ExpectedConditions.visibilityOf(element)); }
此方案无需修改页面对象类,直接沿用原有调用方式即可。
2. 调整测试类的初始化顺序
先执行setup初始化driver,再创建LoginPage实例:
public class OpenBrowser { static WebDriver driver; public static void main(String[] args) { ReusableComponents common = new ReusableComponents(driver); common.setup(); // 确保driver初始化完成后再创建LoginPage LoginPage login = new LoginPage(common.driver); common.waitElementToAppear(login.in_username); login.enterUname("Admin"); login.enterPassword("admin123"); login.clickSubmit(); common.closeBrowser(); } }
3. 优化页面对象类的driver管理
由于LoginPage继承了ReusableComponents,无需重复声明driver变量:
public class LoginPage extends ReusableComponents { @FindBy(xpath="//input[@name='username']") public WebElement in_username; @FindBy(xpath="//input[@name='password']") WebElement in_password; @FindBy(xpath="//button[@type='submit']") WebElement btn_submit; public LoginPage(WebDriver driver) { super(driver); PageFactory.initElements(driver, this); } // 其余方法不变 }
内容的提问来源于stack exchange,提问作者Test Bite
相关产品推荐
相关产品推荐

