Java+Selenium实现POM-PageFactory时WebDriver重复实例化求助
解决Selenium POM-PageFactory模式下重复创建WebDriver实例的问题
嗨,我来帮你搞定这个困扰!你遇到的两个Chrome实例启动的问题,根源其实是继承导致的构造器重复调用:
你的TestClass继承了BaseClass,当TestClass实例化时会先调用BaseClass的构造器,里面的init("chrome")创建了第一个driver;然后在launch()方法里你又new了PageClass,而PageClass也继承了BaseClass,所以又会触发BaseClass的构造器,再次调用init创建第二个driver。
下面给你几个可行的解决方案,都是实际项目里常用的实践:
方案1:给BaseClass的driver加单例判断
修改BaseClass的构造器和init方法,确保driver只被初始化一次:
public class BaseClass { public static WebDriver driver; public BaseClass() { // 仅当driver未初始化时才调用init if (driver == null) { init("chrome"); } } public void init(String browser) { // 双重校验,避免多线程下的重复创建(如果用并行测试的话) if (driver == null) { switch(browser) { case "chrome": driver = new ChromeDriver(); break; // 可以添加其他浏览器的case,比如firefox、edge } } } public void navigate(String url) { driver.get(url); } }
这种方式能快速解决问题,但要注意如果是并行测试的话,静态driver可能会有线程安全问题,不过单线程测试完全没问题。
方案2:让测试类统一管理driver生命周期(推荐)
更规范的做法是把driver的初始化和销毁完全交给测试类负责,BaseClass只提供通用工具方法,避免构造器里自动初始化:
修改后的BaseClass
public class BaseClass { protected static WebDriver driver; // 用protected让子类可以访问 // 移除构造器里的init调用 public BaseClass() {} public void init(String browser) { switch(browser) { case "chrome": driver = new ChromeDriver(); break; // 其他浏览器配置 } } public void navigate(String url) { driver.get(url); } // 新增销毁方法,测试结束后关闭driver public void tearDown() { if (driver != null) { driver.quit(); driver = null; // 重置driver,避免影响后续测试 } } }
修改后的PageClass
public class PageClass extends BaseClass{ @FindBy(id = "APjFqb") // 这里填实际的元素定位符,比如Google搜索框的id WebElement searchTxtBox; public PageClass() { // 用已初始化的driver来初始化PageFactory PageFactory.initElements(driver, this); } public void enterSearchString(String text) { searchTxtBox.sendKeys(text); } public void clickSearchBtn() { searchTxtBox.submit(); // 或者定位搜索按钮后点击 } }
修改后的TestClass
public class TestClass extends BaseClass { PageClass page; @BeforeClass public void launch() { init("chrome"); // 这里只初始化一次driver page = new PageClass(); // 此时driver已经存在,不会重复创建 } @Test public void searchForSomething() { navigate("https://google.com"); page.enterSearchString("Selenium"); page.clickSearchBtn(); } @AfterClass public void cleanUp() { tearDown(); // 测试结束后关闭浏览器 } }
这种方案的优势是driver的生命周期完全可控,测试开始前初始化,结束后销毁,不会出现意外的重复实例,也更符合POM模式的设计思想——页面对象只负责元素和页面操作,测试类负责测试流程和环境准备。
额外小提示
- 如果你用的是TestNG并行测试,静态driver会有线程安全问题,这时候可以用
ThreadLocal<WebDriver>来存储driver,每个线程拥有独立的实例。 - 页面对象类里的元素定位符要确保准确,比如
@FindBy里要填具体的定位方式(id、name、xpath等),不然PageFactory无法找到元素。
内容的提问来源于stack exchange,提问作者A-K
相关产品推荐
相关产品推荐

