所以我正在使用 javaFX 制作一个学校项目,我需要使用 junit 5 进行测试。但是当我尝试运行测试时,我收到 ExceptionInitializeError 因为“ToolKit”未初始化。我如何初始化这个工具包?
public class RegisterTest {
private Register register;
private User user;
@BeforeEach
public void setUp() {
register = new Register();
register.username = new TextField();
register.email = new TextField();
register.password = new TextField();
register.confirmPassword = new TextField();
user = mock(User.class);
}
@Test
public void testValidUser() {
when(user.checkNewUsername(anyString())).thenReturn(true);
when(user.checkNewEmail(anyString())).thenReturn(true);
when(user.checkNewPassword(anyString())).thenReturn(true);
assertTrue(register.validUser());
}
我问了chatgtp,我给了我一个运行@Beforeall的初始化程序。但 JFXpanel 来自一个库,我不使用调用“swing”。
@BeforeAll
public static void initToolkit() {
new JFXPanel(); // Initializes the JavaFX toolkit
}
BeforeAll
public static void initToolkit() {
if (!Platform.isFxApplicationThread()) {
Platform.startup(() -> {});
}
}
JavaFX 中与 UI 直接相关的所有类都需要初始化 JavaFX 工具包才能使用它们。如果您想测试使用 JavaFX 的代码,那么我建议您将 TestFX 库 添加到您的项目中。链接存储库的自述文件提供了文档。注意 除了 JUnit 5 之外,TestFX 还具有适用于 JUnit 4 和 Spock 的模块。
如果您不想引入库或只是不需要 TestFX 的所有功能,那么您必须确保在自己执行任何相关测试之前启动 JavaFX。您还需要确保 JavaFX 在执行所有测试后退出。
如果您拥有的只是一个具有 JavaFX 相关测试的单个测试类,那么您应该能够摆脱:
import javafx.application.Platform;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
class MyTests {
@BeforeAll
static void startPlatform() {.
Platform.startup(() -> {});
}
@AfterAll
static void exitPlatform() {
Platform.exit();
}
// tests ...
}
注意:如果没有必要,等待 JavaFX 平台完全初始化后再执行任何测试可能更合适。有关如何执行此操作的想法,请参阅下面的扩展实现。
每个 JVM 实例只能调用
Platform::startup(Runnable)
方法一次,否则会抛出异常。并且一旦退出,JavaFX 就无法在同一个 JVM 中再次启动。因此,如果您有多个测试类以及 JavaFX 相关测试,我建议您将启动/退出移动到 JUnit 扩展中。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import javafx.application.Platform;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
import org.junit.jupiter.api.extension.ExtensionContext.Store;
public class JFXPlatformExtension implements BeforeAllCallback {
@Override
public void beforeAll(ExtensionContext context) throws Exception {
var store = context.getRoot().getStore(Namespace.GLOBAL);
var state = store.getOrComputeIfAbsent(JavaFXState.class);
state.ensureStarted();
}
private static class JavaFXState implements Store.CloseableResource {
private final AtomicBoolean started = new AtomicBoolean();
private final CountDownLatch startupLatch = new CountDownLatch(1);
void ensureStarted() throws InterruptedException {
if (started.compareAndSet(false, true)) {
Platform.startup(startupLatch::countDown);
}
startupLatch.await();
}
@Override
public void close() throws Throwable {
Platform.exit();
}
}
}
使用它看起来像:
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith(JFXPlatformExtension.class)
class MyTests {
// tests ...
}
如果需要,您可以创建自己的组合注释来代替
@ExtendWith
:
import java.lang.annotation.*;
import org.junit.jupiter.api.extension.ExtendWith;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@ExtendWith(JFXPlatformExtension.class)
public @interface JFXTestContainer {}
您可以添加更多功能:
InvocationInterceptor
扩展来完成。
TestInstancePostProcessor
和 ParameterResolver
扩展来完成。