如何测试JavaFX控制器的方法?

时间:2015-03-11 03:38:50

标签: java unit-testing javafx-8

我试图使用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

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

IllegalStateException与JavaFX和TestFX 的性质有关。

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

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

然而,这会引发NullPointerException,这是由与new Flow(ManageCtrl.class)一起使用的 DataFX 的性质引起的。

new Flow(ManageCtrl.class).startInStage(stage)会在控制器中注入所有@FXML个带注释的字段,而@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,试图简化这方面的测试。