Unit testing 使用TestNG对JavaFX2应用程序进行单元测试
我编写了一个相当复杂的JavaFX2应用程序,我想为它编写一系列单元测试。问题是,当我尝试进行测试时,我收到一个运行时错误,抱怨工具箱未初始化 据我所知,我应该以某种方式调用@BeforeClass方法中的Application.launch(),但这会导致死锁,因为Application.launch()不会返回调用线程 所以问题是我应该如何初始化JavaFx 这是不起作用的代码的框架:Unit testing 使用TestNG对JavaFX2应用程序进行单元测试,unit-testing,javafx-2,testng,Unit Testing,Javafx 2,Testng,我编写了一个相当复杂的JavaFX2应用程序,我想为它编写一系列单元测试。问题是,当我尝试进行测试时,我收到一个运行时错误,抱怨工具箱未初始化 据我所知,我应该以某种方式调用@BeforeClass方法中的Application.launch(),但这会导致死锁,因为Application.launch()不会返回调用线程 所以问题是我应该如何初始化JavaFx 这是不起作用的代码的框架: public class AppTest extends Application { @Befo
public class AppTest extends Application {
@BeforeClass
public void initialize() {
launch(); //this causes a deadlock
}
@Test
public void test1() {
//conduct test here
}
@Test
public void test2() {
//conduct other test here
}
@Override
public void start(Stage arg0) throws Exception {
}
提前谢谢 好吧,考虑到您的JavaFX应用程序可能位于项目根/src/main/java/package/FXApp.java,那么您的测试可能位于其他位置,如项目根/src/test/java/package/FXAppTest.java。在这种情况下,FXAppTest类可以通过使用BeforeClass初始化FXApp类来调用它 从理论上讲,您应该能够通过以下方式启动您的FX应用程序:
// imports located here that import junit 4.11+ packages (or TestNG)
public class FXAppTest {
@BeforeClass
public void initialize() {
FXApp fxa = new FXApp();
while ( fxa.isLoading() ) {
// do nothing
}
}
....
注意:请注意,FXAppTest不会在此处扩展应用程序
现在,如果这不能提示您进入这个问题,您可以在JVM上启用JMX ARG,然后用JVisualVM查看锁定的线程。
主要考虑的是在FX线程内运行您的测试。当您创建一个类扩展应用程序时,实际上您创建了一个进程。这就是您要测试的内容
所以,要在应用程序上启动一些单元测试,首先创建一个扩展应用程序的FXAppTest,然后在FXAppTest内部启动单元测试。这是我的想法 下面是一个JUnit示例。我创建了一个运行程序,在FXApp中启动测试以进行测试。 下面是FxApplicationTest的代码示例(我们在其中启动单元测试) 跑步者:import org.apache.log4j.Logger;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
public class JUnitFxRunner extends Runner {
private final BlockJUnit4ClassRunner runner;
private final Logger LOGGER = Logger.getLogger(JUnitFxRunner.class);
public JUnitFxRunner(final Class<?> klass) throws InitializationError {
super();
runner = new BlockJUnit4ClassRunner(klass);
}
@Override
public Description getDescription() {
return Description.EMPTY;
}
@Override
public void run(final RunNotifier notifier) {
try {
final FxApplicationTest fxApplicationTest = new FxApplicationTest();
MyTestRunner runnable = new MyTestRunner(runner, notifier, fxApplicationTest);
new Thread(runnable).start();
Thread.sleep(100);
runnable.execute();
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
private class MyTestRunner implements Runnable {
private final BlockJUnit4ClassRunner runner;
private final RunNotifier notifier;
private final FxApplicationTest fxApp;
public MyTestRunner(final BlockJUnit4ClassRunner runner, final RunNotifier notifier, final FxApplicationTest fxApp) {
this.runner = runner;
this.notifier = notifier;
this.fxApp = fxApp;
}
@Override
public void run() {
fxApp.startApp();
}
public void execute() throws InterruptedException {
fxApp.execute(runner, notifier);
}
}
}
此单元测试MainFxApp
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class MainFxApp extends Application {
@Override
public void start(final Stage stage) throws Exception {
StackPane root = new StackPane();
Scene scene = new Scene(root, 10, 10);
stage.setScene(scene);
}
public static void main(final String[] args) {
launch(args);
}
}
当然,这段代码需要检查。这只是为了表达这个想法 从stackoverflow开始,我创建了一个小助手类:
import javafx.application.Application;
import javafx.stage.Stage;
public class JavaFXInitializer extends Application {
private static Object barrier = new Object();
@Override
public void start(Stage primaryStage) throws Exception {
synchronized(barrier) {
barrier.notify();
}
}
public static void initialize() throws InterruptedException {
Thread t = new Thread("JavaFX Init Thread") {
public void run() {
Application.launch(JavaFXInitializer.class, new String[0]);
}
};
t.setDaemon(true);
t.start();
synchronized(barrier) {
barrier.wait();
}
}
}
然后可以在@BeforeClass设置方法中轻松使用:
@BeforeClass
public void setup() throws InterruptedException {
JavaFXInitializer.initialize();
}
您可能还想看看JavaFX团队用来测试其软件的方法
import javafx.application.Application;
import javafx.stage.Stage;
public class JavaFXInitializer extends Application {
private static Object barrier = new Object();
@Override
public void start(Stage primaryStage) throws Exception {
synchronized(barrier) {
barrier.notify();
}
}
public static void initialize() throws InterruptedException {
Thread t = new Thread("JavaFX Init Thread") {
public void run() {
Application.launch(JavaFXInitializer.class, new String[0]);
}
};
t.setDaemon(true);
t.start();
synchronized(barrier) {
barrier.wait();
}
}
}
@BeforeClass
public void setup() throws InterruptedException {
JavaFXInitializer.initialize();
}