在 Java 中测试覆盖事件处理程序(JavaFx,Spring 启动)
Testing overriden EventHandler in Java (JavaFx, Spring Boot)
我一直在 Java 使用 Spring Boot 和 JavaFX 前端编写一个小应用程序。
我无法弄清楚如何测试其中一个控制器的一部分。具体来说,控制器包括一些事件处理,用于在 'confirm' 或 'cancel' 按钮被按下时进行处理。按确认应该会导致所选项目从数据库和表格视图中删除。按任一按钮应该会导致当前 window 关闭。
package application.controllers;
import ...
@Controller
public class ConfirmDeleteController {
@FXML private Label labelConfirmDelete;
@FXML private Button confirmButton;
@FXML private Button cancelButton;
private FooService fooService;
private TableView<Foo> fooTable;
private Foo foo = new foo();
void initData(TableView<Foo> fooTable, FooService fooService) {
this.fooTable = fooTable;
this.fooService = fooService;
foo = (Foo) fooTable.getSelectionModel().getSelectedItem();
[other irrelevant bits with test coverage already]
initializeButtonEventHandling();
}
private void initializeButtonEventHandling() {
confirmButton.defaultButtonProperty().bind(confirmButton.focusedProperty());
cancelButton.defaultButtonProperty().bind(cancelButton.focusedProperty());
confirmButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
fooService.delete(foo); // Delete from db
fooTable.getItems().remove(foo); // Delete from the table view
confirmButton.getScene().getWindow().hide(); // Close this pop up
}
});
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
cancelButton.getScene().getWindow().hide();
}
});
}
}
为了测试,我有:
public class TestConfirmDeleteController extends ApplicationTest {
@Mock private Foo foo;
@Mock private FooService fooService;
@Mock private TableViewSelectionModel<Foo> selectionModel;
@Mock private TableView<Foo> fooTable;
private ConfirmDeleteController confirmDeleteController;
@Override
public void start (Stage stage) throws Exception {
// Mock core behaviour
initMocks(this);
when(fooTable.getSelectionModel()).thenReturn(selectionModel);
when(selectionModel.getSelectedItem()).thenReturn(foo);
// Load and display
FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getResource("/fxml/popups/ConfirmDelete.fxml"));
stage.setScene(new Scene((Pane) fxmlLoader.load()));
confirmDeleteController =
fxmlLoader.<ConfirmDeleteController>getController();
stage.show();
}
...
@SuppressWarnings("unchecked")
@Test
public void testConfirmDeletion() {
// Given
ObservableList<Foo> listOfFoo = mock(ObservableList.class);
Scene scene = mock(Scene.class);
Window window = mock(Window.class);
when(fooTable.getItems()).thenReturn(listOfFoo);
when(listOfFoo.remove(foo)).thenReturn(true);
when(scene.getWindow()).thenReturn(window);
// When
confirmDeleteController.initData(fooTable, fooService);
clickOn("#confirmButton");
// Then
verify(fooService).delete(foo); // Delete from database
verify(listOfFoo).remove(foo); // Delete from TableView
verify(window).hide(); // Close the confirm delete window
}
我尝试了几种触发事件的方法,但都没有成功。我试过用模拟替换按钮,注入它,然后直接触发事件。我试过使用 TestFX 机器人按下按钮(如上所述)。在这种情况下,您可以看到机器人单击按钮,但断言失败,表明所选项目未被删除等。
每种方法都感觉有点 'badly-executed integration test-esque',所以我觉得我什至可能需要重构它以将事件处理移到别处?
有人可以建议如何解决这个问题并获得适当的测试覆盖率吗?这个阶段我都在用头撞墙了。
我知道代码有效,因为我已经对其进行了广泛的手动测试,但不知道如何对其进行单元测试。
谢谢。
编辑:我现在发现这个问题实际上与我 Mac 上的安全和隐私设置有关。见下文。
如果有人对未来感兴趣,这里的问题实际上与 Mac OS Catalina 上的安全和隐私设置有关。 Eclipse 没有控制计算机的权限(设置 --> 安全和隐私 --> 辅助功能 --> "Allow the apps below to control your computer".
因此,FxRobot 无法真正点击按钮。您可以看到鼠标在移动,但结果什么也没发生。
更新上述设置,重新启动 Eclipse,然后重新运行 测试允许测试实际单击按钮,然后按预期触发事件。
我一直在 Java 使用 Spring Boot 和 JavaFX 前端编写一个小应用程序。
我无法弄清楚如何测试其中一个控制器的一部分。具体来说,控制器包括一些事件处理,用于在 'confirm' 或 'cancel' 按钮被按下时进行处理。按确认应该会导致所选项目从数据库和表格视图中删除。按任一按钮应该会导致当前 window 关闭。
package application.controllers;
import ...
@Controller
public class ConfirmDeleteController {
@FXML private Label labelConfirmDelete;
@FXML private Button confirmButton;
@FXML private Button cancelButton;
private FooService fooService;
private TableView<Foo> fooTable;
private Foo foo = new foo();
void initData(TableView<Foo> fooTable, FooService fooService) {
this.fooTable = fooTable;
this.fooService = fooService;
foo = (Foo) fooTable.getSelectionModel().getSelectedItem();
[other irrelevant bits with test coverage already]
initializeButtonEventHandling();
}
private void initializeButtonEventHandling() {
confirmButton.defaultButtonProperty().bind(confirmButton.focusedProperty());
cancelButton.defaultButtonProperty().bind(cancelButton.focusedProperty());
confirmButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
fooService.delete(foo); // Delete from db
fooTable.getItems().remove(foo); // Delete from the table view
confirmButton.getScene().getWindow().hide(); // Close this pop up
}
});
cancelButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
cancelButton.getScene().getWindow().hide();
}
});
}
}
为了测试,我有:
public class TestConfirmDeleteController extends ApplicationTest {
@Mock private Foo foo;
@Mock private FooService fooService;
@Mock private TableViewSelectionModel<Foo> selectionModel;
@Mock private TableView<Foo> fooTable;
private ConfirmDeleteController confirmDeleteController;
@Override
public void start (Stage stage) throws Exception {
// Mock core behaviour
initMocks(this);
when(fooTable.getSelectionModel()).thenReturn(selectionModel);
when(selectionModel.getSelectedItem()).thenReturn(foo);
// Load and display
FXMLLoader fxmlLoader = new FXMLLoader(
getClass().getResource("/fxml/popups/ConfirmDelete.fxml"));
stage.setScene(new Scene((Pane) fxmlLoader.load()));
confirmDeleteController =
fxmlLoader.<ConfirmDeleteController>getController();
stage.show();
}
...
@SuppressWarnings("unchecked")
@Test
public void testConfirmDeletion() {
// Given
ObservableList<Foo> listOfFoo = mock(ObservableList.class);
Scene scene = mock(Scene.class);
Window window = mock(Window.class);
when(fooTable.getItems()).thenReturn(listOfFoo);
when(listOfFoo.remove(foo)).thenReturn(true);
when(scene.getWindow()).thenReturn(window);
// When
confirmDeleteController.initData(fooTable, fooService);
clickOn("#confirmButton");
// Then
verify(fooService).delete(foo); // Delete from database
verify(listOfFoo).remove(foo); // Delete from TableView
verify(window).hide(); // Close the confirm delete window
}
我尝试了几种触发事件的方法,但都没有成功。我试过用模拟替换按钮,注入它,然后直接触发事件。我试过使用 TestFX 机器人按下按钮(如上所述)。在这种情况下,您可以看到机器人单击按钮,但断言失败,表明所选项目未被删除等。
每种方法都感觉有点 'badly-executed integration test-esque',所以我觉得我什至可能需要重构它以将事件处理移到别处?
有人可以建议如何解决这个问题并获得适当的测试覆盖率吗?这个阶段我都在用头撞墙了。
我知道代码有效,因为我已经对其进行了广泛的手动测试,但不知道如何对其进行单元测试。
谢谢。
编辑:我现在发现这个问题实际上与我 Mac 上的安全和隐私设置有关。见下文。
如果有人对未来感兴趣,这里的问题实际上与 Mac OS Catalina 上的安全和隐私设置有关。 Eclipse 没有控制计算机的权限(设置 --> 安全和隐私 --> 辅助功能 --> "Allow the apps below to control your computer".
因此,FxRobot 无法真正点击按钮。您可以看到鼠标在移动,但结果什么也没发生。
更新上述设置,重新启动 Eclipse,然后重新运行 测试允许测试实际单击按钮,然后按预期触发事件。