JUnit5中@RegisterExtension如何传递动态WebDriver实例?
问题原因
你遇到的核心问题是Java的引用传递机制:
- 测试类初始化时,
@RegisterExtension的TakeScreenshotOnFailure实例通过构造函数接收了最初的driver引用。 - 后续在
@BeforeEach中重新给driver变量赋值(driver = initializeBrowser("chrome")),只是改变了测试类中driver变量的指向,但扩展类里存储的还是原来已quit的旧driver引用,因此截图时会使用失效实例。
解决方案
下面提供两种实用的解决思路,可根据你的代码习惯选择:
方案一:从测试实例中动态获取最新Driver
让扩展类通过ExtensionContext直接从测试类实例中读取当前的driver,避免构造函数传入固定引用的问题。
修改扩展类代码
import Test.BaseTest; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestWatcher; import org.openqa.selenium.WebDriver; import ru.yandex.qatools.ashot.AShot; import ru.yandex.qatools.ashot.Screenshot; import javax.imageio.ImageIO; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; public class TakeScreenshotOnFailure2 extends BaseTest implements TestWatcher { @Override public void testFailed(ExtensionContext context, Throwable cause) { WebDriver driver = getCurrentDriverFromTestInstance(context); if (driver == null) return; // 处理截图名称,避免非法字符 String screenShotName = context.getDisplayName().replaceAll("[^a-zA-Z0-9]", "_"); String screenShotPath = "./screenshots/" + screenShotName + ".png"; try { // 自动创建截图目录 new File("./screenshots").mkdirs(); Screenshot screenshot = new AShot().takeScreenshot(driver); ImageIO.write(screenshot.getImage(), "PNG", new File(screenShotPath)); } catch (IOException e) { throw new RuntimeException("截图保存失败", e); } finally { driver.quit(); } } @Override public void testSuccessful(ExtensionContext context) { WebDriver driver = getCurrentDriverFromTestInstance(context); if (driver != null) driver.quit(); } // 通过反射从测试实例中获取最新driver private WebDriver getCurrentDriverFromTestInstance(ExtensionContext context) { try { Object testInstance = context.getRequiredTestInstance(); Field driverField = testInstance.getClass().getDeclaredField("driver"); driverField.setAccessible(true); return (WebDriver) driverField.get(testInstance); } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException("无法获取测试类中的driver实例", e); } } }
修改测试类代码
测试类无需再给扩展类传入driver,直接初始化扩展实例即可:
import Test.OpenPageFactory; import Test.TakeScreenshotOnFailure2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.RegisterExtension; import org.openqa.selenium.WebDriver; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class Tests2 extends BaseTest { WebDriver driver = initializeBrowser("chrome"); OpenPageFactory openPageFactory = new OpenPageFactory(driver); // 无需传入driver,扩展类会动态获取 @RegisterExtension public TakeScreenshotOnFailure2 takeScreenshotOnFailure = new TakeScreenshotOnFailure2(); @BeforeEach public void setUp() { if (driver == null || driver.toString().contains("null")) { driver = initializeBrowser("chrome"); openPageFactory = new OpenPageFactory(driver); } } @Test public void verifyAllLinksWithNotLoggedInUser() throws InterruptedException { openPageFactory.goToHomePage(); } @Test public void negativeTestSignInWithInvalidData() throws Exception { openPageFactory.goToSignInPage(); } }
方案二:用容器类封装Driver(避免反射)
定义一个简单的容器类存储driver,让扩展类引用这个容器,这样每次更新容器内的driver,扩展类就能拿到最新实例。
定义Driver容器类
import org.openqa.selenium.WebDriver; public class DriverContainer { private WebDriver driver; public WebDriver getDriver() { return driver; } public void setDriver(WebDriver driver) { this.driver = driver; } }
修改测试类代码
import Test.OpenPageFactory; import Test.TakeScreenshotOnFailure2; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.extension.RegisterExtension; import org.openqa.selenium.WebDriver; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class Tests2 extends BaseTest { // 用容器存储driver private DriverContainer driverContainer = new DriverContainer(); OpenPageFactory openPageFactory; // 给扩展类传入容器 @RegisterExtension public TakeScreenshotOnFailure2 takeScreenshotOnFailure = new TakeScreenshotOnFailure2(driverContainer); @BeforeEach public void setUp() { WebDriver driver = initializeBrowser("chrome"); driverContainer.setDriver(driver); openPageFactory = new OpenPageFactory(driver); } @Test public void verifyAllLinksWithNotLoggedInUser() throws InterruptedException { openPageFactory.goToHomePage(); } @Test public void negativeTestSignInWithInvalidData() throws Exception { openPageFactory.goToSignInPage(); } }
修改扩展类代码
import Test.BaseTest; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestWatcher; import org.openqa.selenium.WebDriver; import ru.yandex.qatools.ashot.AShot; import ru.yandex.qatools.ashot.Screenshot; import javax.imageio.ImageIO; import java.io.File; import java.io.IOException; public class TakeScreenshotOnFailure2 extends BaseTest implements TestWatcher { private final DriverContainer driverContainer; public TakeScreenshotOnFailure2(DriverContainer driverContainer) { this.driverContainer = driverContainer; } @Override public void testFailed(ExtensionContext context, Throwable cause) { WebDriver driver = driverContainer.getDriver(); if (driver == null) return; String screenShotName = context.getDisplayName().replaceAll("[^a-zA-Z0-9]", "_"); String screenShotPath = "./screenshots/" + screenShotName + ".png"; try { new File("./screenshots").mkdirs(); Screenshot screenshot = new AShot().takeScreenshot(driver); ImageIO.write(screenshot.getImage(), "PNG", new File(screenShotPath)); } catch (IOException e) { throw new RuntimeException("截图保存失败", e); } finally { driver.quit(); } } @Override public void testSuccessful(ExtensionContext context) { WebDriver driver = driverContainer.getDriver(); if (driver != null) driver.quit(); } }
内容的提问来源于stack exchange,提问作者kribor
相关产品推荐
相关产品推荐

