我试图使用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("[email protected]");

        assertEquals("[email protected]", ((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


谢谢您的帮助。

最佳答案

IllegalStateException与JavaFX和TestFX的性质有关。

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

interact(() -> {
    ManageCtrl controller = new ManageCtrl();
    controller.setEmail("[email protected]");
});


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

@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("[email protected]");
    });

    // then:
    verifyThat("#email", hasText("[email protected]"));
}




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

10-03 00:23