java - 如何对 JavaFX 应用程序启动进行单元测试

标签 java unit-testing javafx javafx-8 testfx

我有一个 JavaFX 应用程序,我想测试它是否启动。我该怎么做呢?仅使用 JUnit 是否可行,或者 TestFX 可以帮助我实现这一点?

我的主要问题是:如何在(成功)启动后立即关闭应用程序?

示例应用程序类:

public class MovieDB extends Application {
    @Override
    public void start(final Stage primaryStage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(MovieDBController.class.getResource("MovieDB.fxml"), ResourceBundle.getBundle("bundles/bundle", new Locale("en")));
        Parent root = fxmlLoader.load();

        Scene scene = new Scene(root, 1024, 768);

        StyleManager.getInstance().addUserAgentStylesheet(getClass().getResource("/css/MovieDB.css").getPath());

        primaryStage.setTitle("MovieDB");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

最佳答案

Application.launch方法在应用程序退出之前不会返回,要么通过调用 Platform.exit或者所有应用程序窗口都已关闭,因此您必须将其包装到另一个线程中才能终止它。

如果您在 JavaFX 应用程序启动后立即调用 Platform.exit,您将获得 IllegalStateException。如果您等待一段时间以便您的 JavaFX 应用程序可以初始化,然后调用 Platform.exit,您的 JavaFX 应用程序和您的包装器线程都将终止,而不会完成或抛出任何异常。我找不到使用 Platform.exit 来解决这个问题的方法。

但是,我设法通过使用 Thread.interrupt 来做到这一点。只需在包装线程内运行您的 JavaFX 应用程序,等待一段时间,然后中断您的包装线程。这样 JavaFX 应用程序将被中断并抛出 InterruptedException。如果它没有抛出,则说明启动 JavaFX 应用程序时出现问题。

请注意,它可能比您等待 JVM 启动 JavaFX 应用程序所花的时间更长,因此此方法不能保证 JavaFX 应用程序在正确启动后会被中断,这可能会导致误报情况。

测试类

import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import static org.junit.Assert.assertTrue;
import org.junit.Test;

public class JavaFXTest {

    // Wrapper thread updates this if
    // the JavaFX application runs without a problem.
    // Declared volatile to ensure that writes are visible to every thread.
    private volatile boolean success = false;

    /**
     * Test that a JavaFX application launches.
     */
    @Test
    public void testMain() {
        Thread thread = new Thread() { // Wrapper thread.
            @Override
            public void run() {
                try {
                    Application.launch(JavaFXTest.class); // Run JavaFX application.
                    success = true;
                } catch(Throwable t) {
                    if(t.getCause() != null && t.getCause().getClass().equals(InterruptedException.class)) {
                        // We expect to get this exception since we interrupted
                        // the JavaFX application.
                        success = true;
                        return;
                    }
                    // This is not the exception we are looking for so log it.
                    Logger.getLogger(JavaFXTest.class.getName()).log(Level.SEVERE, null, t);
                }
            }
        };
        thread.setDaemon(true);
        thread.start();
        try {
            Thread.sleep(3000);  // Wait for 3 seconds before interrupting JavaFX application
        } catch(InterruptedException ex) {
            // We don't care if we wake up early.
        }
        thread.interrupt();
        try {
            thread.join(1); // Wait 1 second for our wrapper thread to finish.
        } catch(InterruptedException ex) {
            // We don't care if we wake up early.
        }
        assertTrue(success);
    }
}

JavaFX 应用程序类

import java.io.IOException;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class JavaFX extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws IOException {
        primaryStage.setTitle("JavaFX");
        Label label = new Label("Hello World!");
        StackPane root = new StackPane();
        root.getChildren().add(label);
        primaryStage.setScene(new Scene(root, 250, 250));
        primaryStage.show();
    }
}

关于java - 如何对 JavaFX 应用程序启动进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24851886/

相关文章:

c# - 什么是 java Vector.element() C# 等价物

objective-c - 如何将 block 的结果模拟为方法参数?

java - 为什么 Selenium 在每个 JUnit 测试项之间创建一个新的 RC 和/或浏览器实例?

javafx使用translatetransition和keyevent在屏幕上 move 图像

JavaFX 在一段时间后隐藏节点

java - 在 java 中保存任何对象创建时的堆栈跟踪,并在程序中的任何其他点使用它

java - 需要有关字符串搜索设计的建议

java - 向 Elasticsearch 添加新的 HTTP 客户端以支持客户端应用程序针对 AWS Elasticsearch 运行?

java - Java 中类似 Python 的文档测试?

java - 在 JavaFX 中调用 swing 软件的 main 函数将终止 JavaFX 软件