Selenium自动化脚本重复执行且浏览器未正常关闭问题排查
问题分析与解决方案
看起来你遇到的核心问题是脚本重复执行、浏览器未正确关闭,结合你的代码和控制台输出,我来帮你拆解原因并给出修复方案:
核心问题根源
- TearDown方法未被自动触发:你的
SeleniumSetup类里的tearDown()只是普通方法,没有添加JUnit/Cucumber的@After注解,导致测试结束后不会自动关闭浏览器,残留的窗口会干扰后续执行。 - 步骤类构造函数触发重复初始化:你在
ChallengingDOMSteps的构造函数里调用prepareBrowserForSelenium(),但Cucumber运行时可能会多次实例化步骤类,加上DriverSingleton的缺失/错误实现,导致每次都重新启动浏览器。 - DriverSingleton单例逻辑缺失:代码里依赖
DriverSingleton维护全局唯一的WebDriver,但你没提供这个类的实现,大概率是单例没有正确保存driver实例,才会出现两次启动ChromeDriver的情况。
具体修复步骤
1. 修复SeleniumSetup的TearDown钩子
给tearDown()添加@After注解,改用quit()彻底关闭浏览器,并清空单例实例:
package support; import org.junit.After; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; public class SeleniumSetup { protected WebDriver driver; public SeleniumSetup() { } public void prepareBrowserForSelenium() { if(DriverSingleton.getDriver() == null) { setup(); } else { driver = DriverSingleton.getDriver(); } } public void setup() { System.setProperty("webdriver.chrome.driver", "C:\\Users\\Selenium and drivers\\chromedriver.exe"); driver = new ChromeDriver(); driver.get("http://the-internet.herokuapp.com/"); driver.manage().window().maximize(); // 将初始化好的driver存入单例 DriverSingleton.setDriver(driver); } @After // 添加上这个注解,让Cucumber自动调用 public void tearDown() { if(driver != null) { driver.quit(); // 用quit()代替close(),彻底终止浏览器进程 DriverSingleton.setDriver(null); // 清空单例,避免下次复用旧实例 } } }
2. 实现正确的DriverSingleton单例类
创建这个类来维护全局唯一的WebDriver实例:
package support; import org.openqa.selenium.WebDriver; public class DriverSingleton { // 私有静态变量存储driver实例 private static WebDriver driver; // 私有构造函数,防止外部实例化 private DriverSingleton() {} public static WebDriver getDriver() { return driver; } public static void setDriver(WebDriver driverInstance) { driver = driverInstance; } }
3. 调整步骤类的初始化逻辑
把构造函数里的初始化逻辑改成Cucumber的@Before钩子,确保每个场景只初始化一次浏览器:
package steps; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; import cucumber.api.java.en.When; import cucumber.api.java.Before; // 导入Before钩子 import pages.ChallengingDOMPage; import pages.DropdownPage; import support.SeleniumSetup; public class ChallengingDOMSteps extends SeleniumSetup{ @Before // 每个测试场景执行前只会调用一次 public void setupBrowser() throws Exception{ prepareBrowserForSelenium(); } @Given("^I am on the landing page$") public void i_am_on_the_landing_page() throws Throwable { new ChallengingDOMPage(driver).landingPage(); } @When("^I select \"(.*?)\"$") public void i_select(String arg1) throws Throwable { new ChallengingDOMPage(driver).selectChallengingDOM(); } @Then("^I will be navigated to the \"(.*?)\" page$") public void i_will_be_navigated_to_the_page(String arg1) throws Throwable { if(arg1.equalsIgnoreCase("Challenging DOM")) new ChallengingDOMPage(driver).verifyChallegingDOMPage(); else if(arg1.equals("Dropdown")) new DropdownPage(driver).verifyDropdownHeading(); } }
关键注意点
quit()vsclose():close()只会关闭当前标签页,quit()会彻底终止浏览器进程,避免后台残留大量未关闭的Chrome实例。- 单例清空:每次tearDown时清空
DriverSingleton的实例,确保下一次测试能初始化全新的浏览器。 - 钩子替代构造函数:Cucumber的步骤类构造函数可能被多次调用,用
@Before钩子能保证浏览器初始化逻辑只执行一次。
内容的提问来源于stack exchange,提问作者awalker23
相关产品推荐
相关产品推荐

