【问题标题】:How to test method of JavaFX controller?如何测试 JavaFX 控制器的方法?
【发布时间】:2015-05-12 17:50:39
【问题描述】:

我试图使用 TestFX 来测试我的应用程序。我想为我的控制器的方法运行测试。

Main.java:

public class Main extends Application {
    try{
        new Flow(ManageCtrl.class).startInStage(primaryStage);
    } catch (Exception ex) {
        LOGGER.log(Level.SEVERE, null, ex);
    }
}

ManageCtrl.java:

@ViewController("/FPManage.fxml")
public class ManageCtrl extends AnchorPane {

    @FXML // fx:id="email"
    private TextField email; // Value injected by FXMLLoader

    public void setEmail(String address) {
        this.email.setText(address);
    }
}

ManageCtrlTest.java:

public class ManageCtrlTest extends ApplicationTest {

    @Override
    public void start(Stage stage) {
        try {
            new Flow(ManageCtrl.class).startInStage(stage);
        } catch (FlowException ex) {
            Logger.getLogger(ManageCtrlTest.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Test
    public void testSetEmail() {
        ManageCtrl instance = new ManageCtrl();
        instance.setEmail("test@gmai.com");

        assertEquals("test@gmail.com", ((TextField)GuiTest.find("#email")).getText());
    }
}

但我得到以下异常:

testSetEmail Failed: java.lang.illegalStateException: Not on FX application thread; currentThread = Test worker
java.lang.illegalStateException: Not on FX application thread; currentThread = Test Worker

感谢您的帮助。

【问题讨论】:

  • 我从未使用过TestFX,因此该框架可能有特定的解决方案。 Andy Till 创建了一个JUnit rule for testing on the JavaFX application thread。也许您可以根据自己的目的对其进行调整,尽管我希望名为 TestFX 的框架能够本地处理此类事情。
  • 很抱歉在 2 个不同的地方提问。但我从作者那里得到了答案:#207。重点是使用DataFX API:Flow flow = new Flow(ManageCtrl.class); FlowHandler handler = flow.createHandler(); stage.setScene(new Scene(handler.start())); stage.show(); FlowView view = handler.getCurrentView(); controller = (ManageCtrl) view.getViewContext().getController(); 有了那个控制器,我们就可以调用里面的方法了。
  • 5 分钟太短,我无法预览结果。 >.Flow flow = new Flow(ManageCtrl.class); 还是没加换行符,不过帮助说加2个空格会加
    。也未能添加高亮语法。
  • 您可以answer your own question 并将其标记为正确。我建议您通过总结场外信息来做到这一点(因此答案在堆栈溢出时是自包含的)。这比将代码发布到 cmets 中要好。

标签: java unit-testing javafx-8


【解决方案1】:

IllegalStateExceptionJavaFX 和 TestFX 的性质有关。

ManageCtrl 扩展自 AnchorPane,这是 JavaFX 的 Scene 对象之一,所有这些对象都需要在 JavaFX 线程(也称为 JavaFX 应用程序线程或 JavaFX 用户线程)中构建。您可以在 JavaFX 线程中使用ApplicationTest#interact 构造ManageCtrl

interact(() -> {
    ManageCtrl controller = new ManageCtrl();
    controller.setEmail("test@gmail.com");
});

但是这会抛出一个NullPointerException,这是由与new Flow(ManageCtrl.class) 一起使用的DataFX 的性质 引起的。

new Flow(ManageCtrl.class).startInStage(stage) 将在控制器中注入所有@FXML-annotated 字段,其中定义了在@ViewController 中的对象@new ManageCtrl() 不会。我们可以通过在测试前将ManageCtrl构造到controller字段中来解决这个问题:

@Override
public void start(Stage stage) throws Exception {
    Flow flow = new Flow(ManageCtrl.class);

    // create a handler to initialize a view and a sceneRoot.
    FlowHandler handler = flow.createHandler();
    StackPane sceneRoot = handler.start();

    // retrieve the injected controller from the view.
    FlowView view = handler.getCurrentView();
    controller = (ManageCtrl) view.getViewContext().getController();

    // attach the sceneRoot to stage.
    stage.setScene(new Scene(sceneRoot));
    stage.show();
}

您现在可以使用以下方法测试您的控制器:

@Test
public void should_set_email() throws Exception {
    // when:
    interact(() -> {
        controller.setEmail("test@gmail.com");
    });

    // then:
    verifyThat("#email", hasText("test@gmail.com"));
}

整个事情在issue on GitHub 中有详细说明。我还创建了一个pull request on Bitbucket,试图简化这方面的测试。

【讨论】:

    猜你喜欢
    • 2017-06-03
    • 2015-06-29
    • 2012-04-20
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-15
    相关资源
    最近更新 更多