在 junit 5 中测试时 javaFX 工具包未初始化

问题描述 投票:0回答:2

所以我正在使用 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
    }
java intellij-idea javafx junit5 scenebuilder
2个回答
0
投票
BeforeAll
public static void initToolkit() {
    if (!Platform.isFxApplicationThread()) {
        Platform.startup(() -> {});
    }
}

0
投票

JavaFX 中与 UI 直接相关的所有类都需要初始化 JavaFX 工具包才能使用它们。如果您想测试使用 JavaFX 的代码,那么我建议您将 TestFX 库 添加到您的项目中。链接存储库的自述文件提供了文档。注意 除了 JUnit 5 之外,TestFX 还具有适用于 JUnit 4Spock 的模块。


自己动手 - JUnit 5

如果您不想引入库或只是不需要 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 {}

更多功能

您可以添加更多功能:

© www.soinside.com 2019 - 2024. All rights reserved.