You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 06:20:39