使用POM模式的Selenium测试报错:无法实例化FBLoginTest类
使用Selenium页面对象模型(POM)编写测试代码时,出现报错**"Cannot instantiate class co.edureka.tests.FBLoginTest"**,怀疑与重复创建WebDriver实例有关,但未找到解决方法。以下是完整报错信息及相关代码:
相关代码文件
FBLoginPage.java
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.How; public class FBLoginPage { WebDriver driver; public FBLoginPage(WebDriver driver) { this.driver=driver; } @FindBy(how=How.XPATH, using="/html/body/div[1]/div[1]/div[1]/div/div/div/div[2]/div/div[1]/form/div[1]/div[1]/input") public WebElement emailTextBox; @FindBy(how=How.XPATH, using="//input[@type='password'][@name='pass']") WebElement passwordTextBox; @FindBy(how=How.XPATH, using="//input[@type='submit'][@value='Log In']") WebElement signinButton; // 设置邮箱 public void setEmail(String strEmail) { emailTextBox.sendKeys(strEmail); } // 设置密码 public void setPassword(String strPassword) { passwordTextBox.sendKeys(strPassword); } // 点击登录按钮 public void clickOnLoginButton() { signinButton.click(); } }
FBHomePage.java
package co.edureka.pages; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.How; public class FBHomePage { WebDriver driver; public FBHomePage(WebDriver driver) { this.driver=driver; } @FindBy(how=How.XPATH, using="//div[text()='Account Settings']") WebElement profileDropdown; @FindBy(how=How.LINK_TEXT, using="Log Out") WebElement logoutLink; // 点击个人资料下拉菜单 public void clickOnProfileDropdown() { profileDropdown.click(); } // 点击退出链接 public void clickOnLogoutLink() { logoutLink.click(); } }
TestBase.java
package co.edureka.tests; import java.io.IOException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; public class TestBase { public static WebDriver driver; @BeforeSuite public void initialize() throws IOException{ System.setProperty("webdriver.chrome.driver", "C:\\Program Files (x86)\\Drivers\\chromedriver.exe"); driver = new ChromeDriver(); WebDriver driver = new ChromeDriver(); driver.manage().window().maximize(); driver.get("https://www.facebook.com"); } @AfterSuite public void TeardownTest() { TestBase.driver.quit(); } }
FBLoginTest.java
package co.edureka.tests; import java.time.Duration; import org.openqa.selenium.support.PageFactory; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.annotations.Test; import co.edureka.pages.FBHomePage; import co.edureka.pages.FBLoginPage; public class FBLoginTest extends TestBase { WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(30)); @Test public void init() throws Exception{ //driver.get("https://www.facebook.com"); FBLoginPage loginpage = PageFactory.initElements(driver, FBLoginPage.class); wait.until(ExpectedConditions.titleContains("Facebook")); loginpage.setEmail("432547@gmail.com"); loginpage.setPassword("ashish.bakshi@selenium"); loginpage.clickOnLoginButton(); FBHomePage homepage = PageFactory.initElements(driver, FBHomePage.class); homepage.clickOnProfileDropdown(); homepage.clickOnLogoutLink(); } }
报错控制台信息
[RemoteTestNG] detected TestNG version 7.4.0 org.testng.TestNGException: Cannot instantiate class co.edureka.tests.FBLoginTest at org.testng.internal.ObjectFactoryImpl.newInstance(ObjectFactoryImpl.java:30) at org.testng.internal.InstanceCreator.instantiateUsingDefaultConstructor(InstanceCreator.java:193) at org.testng.internal.InstanceCreator.createInstanceUsingObjectFactory(InstanceCreator.java:113) at org.testng.internal.InstanceCreator.createInstance(InstanceCreator.java:79) at org.testng.internal.objects.SimpleObjectDispenser.dispense(SimpleObjectDispenser.java:25) at org.testng.internal.objects.GuiceBasedObjectDispenser.dispense(GuiceBasedObjectDispenser.java:30) at org.testng.internal.ClassImpl.getDefaultInstance(ClassImpl.java:112) at org.testng.internal.ClassImpl.getInstances(ClassImpl.java:165) at org.testng.TestClass.getInstances(TestClass.java:122) at org.testng.TestClass.initTestClassesAndInstances(TestClass.java:102) at org.testng.TestClass.init(TestClass.java:94) at org.testng.TestClass.<init>(TestClass.java:59) at org.testng.TestRunner.initMethods(TestRunner.java:463) at org.testng.TestRunner.init(TestRunner.java:339) at org.testng.TestRunner.init(TestRunner.java:292) at org.testng.TestRunner.<init>(TestRunner.java:223) at org.testng.remote.support.RemoteTestNG6_12$1.newTestRunner(RemoteTestNG6_12.java:33) at org.testng.remote.support.RemoteTestNG6_12$DelegatingTestRunnerFactory.newTestRunner(RemoteTestNG6_12.java:66) at org.testng.ITestRunnerFactory.newTestRunner(ITestRunnerFactory.java:55) at org.testng.SuiteRunner$ProxyTestRunnerFactory.newTestRunner(SuiteRunner.java:659) at org.testng.SuiteRunner.init(SuiteRunner.java:173) at org.testng.SuiteRunner.<init>(SuiteRunner.java:107) at org.testng.TestNG.createSuiteRunner(TestNG.java:1300) at org.testng.TestNG.createSuiteRunners(TestNG.java:1276) at org.testng.TestNG.runSuitesLocally(TestNG.java:1125) at org.testng.TestNG.runSuites(TestNG.java:1063) at org.testng.TestNG.run(TestNG.java:1031) at org.testng.remote.AbstractRemoteTestNG.run(AbstractRemoteTestNG.java:115) at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:251) at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:77) Caused by: java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:79) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:483) at org.testng.internal.ObjectFactoryImpl.newInstance(ObjectFactoryImpl.java:23) ... 29 more Caused by: java.lang.IllegalArgumentException: Input must be set at org.openqa.selenium.internal.Require.nonNull(Require.java:59) at org.openqa.selenium.support.ui.FluentWait.<init>(FluentWait.java:97) at org.openqa.selenium.support.ui.WebDriverWait.<init>(WebDriverWait.java:77) at org.openqa.selenium.support.ui.WebDriverWait.<init>(WebDriverWait.java:46) at co.edureka.tests.FBLoginTest.<init>(FBLoginTest.java:15) at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:67) ... 32 more
解决建议
从报错栈可以看出,核心问题是**WebDriverWait初始化时driver为null**,同时TestBase存在重复创建WebDriver的问题,具体修复步骤如下:
1. 修复TestBase中重复创建WebDriver的问题
TestBase的initialize方法里重复创建了WebDriver实例,其中WebDriver driver = new ChromeDriver();是局部变量,会覆盖静态变量的引用,导致后续操作混乱。删除该行代码,保留静态driver的初始化:
修改后的TestBase.java:
package co.edureka.tests; import java.io.IOException; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.testng.annotations.AfterSuite; import org.testng.annotations.BeforeSuite; public class TestBase { public static WebDriver driver; @BeforeSuite public void initialize() throws IOException{ System.setProperty("webdriver.chrome.driver", "C:\\Program Files (x86)\\Drivers\\chromedriver.exe"); // 移除重复创建的局部driver实例 driver = new ChromeDriver(); driver.manage().window().maximize(); driver.get("https://www.facebook.com"); } @AfterSuite public void TeardownTest() { TestBase.driver.quit(); } }
2. 调整WebDriverWait的初始化时机
FBLoginTest中WebDriverWait作为成员变量,会在类实例化时初始化,但此时TestBase的@BeforeSuite还未执行,driver还是null,导致报错。需要将WebDriverWait的初始化延迟到driver创建完成后,比如用@BeforeMethod注解:
修改后的FBLoginTest.java:
package co.edureka.tests; import java.time.Duration; import org.openqa.selenium.support.PageFactory; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import co.edureka.pages.FBHomePage; import co.edureka.pages.FBLoginPage; public class FBLoginTest extends TestBase { private WebDriverWait wait; @BeforeMethod public void setupWait() { // 在BeforeMethod中初始化wait,此时driver已被BeforeSuite初始化完成 wait = new WebDriverWait(driver, Duration.ofSeconds(30)); } @Test public void init() throws Exception{ FBLoginPage loginpage = PageFactory.initElements(driver, FBLoginPage.class); wait.until(ExpectedConditions.titleContains("Facebook")); loginpage.setEmail("432547@gmail.com"); loginpage.setPassword("ashish.bakshi@selenium"); loginpage.clickOnLoginButton(); FBHomePage homepage = PageFactory.initElements(driver, FBHomePage.class); homepage.clickOnProfileDropdown(); homepage.clickOnLogoutLink(); } }
3. 优化POM页面对象(可选)
页面对象类的构造函数中建议加入PageFactory.initElements,将元素初始化逻辑封装在页面对象内部,符合POM规范:
修改后的FBLoginPage.java:
import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.FindBy; import org.openqa.selenium.support.How; import org.openqa.selenium.support.PageFactory; public class FBLoginPage { WebDriver driver; public FBLoginPage(WebDriver driver) { this.driver = driver; // 在构造函数中初始化页面元素 PageFactory.initElements(driver, this); } @FindBy(how=How.XPATH, using="/html/body/div[1]/div[1]/div[1]/div/div/div/div[2]/div/div[1]/form/div[1]/div[1]/input") public WebElement emailTextBox; @FindBy(how=How.XPATH, using="//input[@type='password'][@name='pass']") WebElement passwordTextBox; @FindBy(how=How.XPATH, using="//input[@type='submit'][@value='Log In']") WebElement signinButton; public void setEmail(String strEmail) { emailTextBox.sendKeys(strEmail); } public void setPassword(String strPassword) { passwordTextBox.sendKeys(strPassword); } public void clickOnLoginButton() { signinButton.click(); } }
对应的FBHomePage.java也做同样修改,测试类中初始化页面对象时就可以简化为:
FBLoginPage loginpage = new FBLoginPage(driver); FBHomePage homepage = new FBHomePage(driver);
内容的提问来源于stack exchange,提问作者Owen Bonham

