我试图使用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的性质有关。ManageCtrl
是AnchorPane
的扩展,而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,试图简化这方面的测试。