gpt4 book ai didi

java - TestFx - 无法访问登录对话框

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:49:51 26 4
gpt4 key购买 nike

我有一个简单的 javafx 应用程序,在 stage.show() 之后,我调用了登录对话框。当我运行测试时,直到登录对话框被填充并手动确认后,它们才会开始工作。出于测试目的,我尝试在舞台上单击一个按钮后显示另一个对话框,并且通过 testFx 操作它没有问题。唯一的问题是初始登录对话框。有没有办法解决此问题,还是我做错了什么?

测试场景:

主程序.java

package cz.mono.monofx;

import cz.mono.monofx.fxml.LoginDialog;
import cz.mono.monofx.fxml.ScreensController;
import java.util.Optional;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.util.Pair;


public class MainApp extends Application {

public static final String SCREEN1 = "scene";
private final String screen1fxml = "/fxml/Scene.fxml";
public static final String SCREEN2 = "scene2";
private final String screen2fxml = "/fxml/Scene2.fxml";

@Override
public void start(Stage stage) throws Exception {

ScreensController mainContainer = new ScreensController();
mainContainer.loadScreen(SCREEN1, screen1fxml);
mainContainer.loadScreen(SCREEN2, screen2fxml);

mainContainer.setScreen(SCREEN1);

Group root = new Group();
root.getChildren().addAll(mainContainer);

Scene scene = new Scene(root);
scene.getStylesheets().add("/styles/Styles.css");

stage.setTitle("Aplipikacka");
stage.setScene(scene);
stage.show();

LoginDialog login = new LoginDialog();
Optional <Pair<String, String>> result = login.getResult();
}

/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}

}

TestFxBase.java

    package cz.mono.monofx.test;

import cz.mono.monofx.MainApp;
import java.util.concurrent.TimeoutException;
import javafx.scene.Node;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseButton;
import javafx.stage.Stage;
import org.junit.After;
import org.junit.Before;
import org.testfx.api.FxToolkit;
import org.testfx.framework.junit.ApplicationTest;

public class TestFxBase extends ApplicationTest {

@Before
public void setUpClass() throws Exception {
ApplicationTest.launch(MainApp.class);
}

@After
public void afterEachTest() throws TimeoutException {
FxToolkit.hideStage();
release(new KeyCode[]{});
release(new MouseButton[]{});
}

//Helper method to retrieve javafx components
public <T extends Node> T find(String query) {
return (T) lookup(query).queryAll().iterator().next();
}

@Override
public void start(Stage stage) {
stage.show();
}
}

简单测试.java

    package cz.mono.monofx.test;

import static javafx.scene.input.KeyCode.TAB;
import org.junit.Test;

public class ValidationTest extends TestFxBase {

@Test
public void verifyLogin() {
clickOn("#dialogButton");
sleep(1000);
type(TAB);
sleep(1000);
type(TAB);
sleep(1000);
}
}

登录对话框.java

package cz.mono.monofx.fxml;

import java.util.Optional;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.ButtonBar.ButtonData;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.util.Pair;

public class LoginDialog {

private Dialog<Pair<String, String>> dialog;
private TextField username;
private PasswordField password;
private Optional<Pair<String, String>> result;

public LoginDialog() {
dialog = new Dialog<>();
dialog.setTitle("Login");
dialog.setHeaderText("Provide correct login informations.");

username = new TextField();
username.setPrefSize(150, 30);
username.setPromptText("username");
username.setId("username");

//Request focus on username by default
Platform.runLater(()-> username.requestFocus());

password = new PasswordField();
password.setPrefSize(150, 30);
password.setPromptText("password");
password.setId("password");

ButtonType loginButtonType = new ButtonType("Login", ButtonData.OK_DONE);
dialog.getDialogPane().getButtonTypes().addAll(loginButtonType, ButtonType.CANCEL);

Node loginButton = dialog.getDialogPane().lookupButton(loginButtonType);
loginButton.setId("loginButton");
BooleanBinding bb = Bindings.createBooleanBinding(()-> username.getText().isEmpty() || password.getText().isEmpty(), username.textProperty(), password.textProperty());
loginButton.disableProperty().bind(bb);

GridPane grid = new GridPane();
grid.setVgap(10);
grid.setHgap(10);
grid.setPadding(new Insets(20, 150, 10, 10));

grid.add(new Label("Username: "), 0, 0);
grid.add(username, 0, 1);
grid.add(new Label("Password"), 1, 0);
grid.add(password, 1, 1);

dialog.getDialogPane().setContent(grid);

// Convert the result to a username-password-pair when the login button is clicked.
dialog.setResultConverter(dialogButton -> {
if (dialogButton == loginButtonType) {
return new Pair<>(username.getText(), password.getText());
}
return null;
});

result = dialog.showAndWait();
result.ifPresent(usernamePassword -> {
System.out.println("Username=" + usernamePassword.getKey() + ", Password=" + usernamePassword.getValue());
});
if (!result.isPresent()) {
System.exit(0);
};

}

/**
* @return the result
*/
public Optional<Pair<String, String>> getResult() {
return result;
}
}

最佳答案

让我展示一种可行的解决方案。我在我的项目中成功地使用了它。

主要思想是让 start 应用程序方法尽可能少:

public class MainApp extends Application {
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(new MainPane(stage)));
stage.show();
}

所有的逻辑都移到了MainPane类:

class MainPane extends BorderPane {
MainPane(final Stage stage) {
stage.setTitle("Aplipikacka");

// open the login dialog only when the stage is opened too.
stage.setOnShown(event -> Platform.runLater(this::showLoginDialog));
}

private void showLoginDialog() {
LoginDialog login = new LoginDialog();
Optional<Pair<String, String>> result = login.getResult();
// TODO finish here
}
}

因为 textFx 提供了自己的 stage,您应该在其中手动注入(inject)场景,然后执行下一步:

public class TestFxBase extends ApplicationTest {
@Override
public void start(Stage stage) {
stage.setScene(new Scene(new MainPane(stage)));
stage.show();
}
}

最后改进一下测试:

public class MainAppFIT extends TestFxBase {
@Test
public void verifyLogin() {
// given started application and opened login dialog
sleep(500);

// when
write("HelloWorld");
type(TAB);
write("password");
clickOn("#loginButton");

// then
// TODO finish here with verification of actual result
}
}

因此,我能够看到 textfx 机器人如何按照测试步骤中的定义点击/键入。

顺便说一句,`MainAppFIT' - FIT 表示功能集成测试。

关于java - TestFx - 无法访问登录对话框,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45458068/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com