我有一个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);
}
}
答案 0 :(得分:2)
由于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);
}
}
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();
}
}
答案 1 :(得分:0)
假设primaryStage是唯一的开放阶段,当您调用primaryStage.hide()时,JavaFX线程将自动关闭。这是因为默认情况下JavaFX设置为在隐藏所有阶段时关闭,可以通过调用Platform.setImplicitExit(false)
来更改。
更多信息here。