2

我一直在使用带有 JavaFX 前端的 Spring Boot 用 Ja​​va 编写一个小型应用程序。

我无法确定如何测试其中一个控制器的一部分。具体来说,控制器包括一些事件处理,用于何时按下“确认”或“取消”按钮。按确认应该会导致从数据库和表格视图中删除所选项目。按任一按钮应导致当前窗口关闭。

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 机器人按下按钮(如上)。在这种情况下,您可以看到机器人单击按钮,但断言失败,表明所选项目未被删除等。

每种方法都感觉有点“执行不力的集成测试式”,所以我觉得我什至可能需要重构它以将事件处理移到其他地方?

有人可以建议如何解决这个问题并获得适当的测试覆盖率吗?在这个阶段,我正在用头撞墙。

我知道代码有效,因为我已经对其进行了广泛的手动测试,但无法弄清楚如何对其进行单元测试。

谢谢你。

编辑:我现在发现这个问题实际上与我的 Mac 上的安全和隐私设置有关。见下文。

4

1 回答 1

0

如果有人对未来感兴趣,这里的问题实际上与 Mac OS Catalina 上的安全和隐私设置有关。Eclipse 没有控制计算机的权限(设置 --> 安全和隐私 --> 辅助功能 --> “允许下面的应用程序控制您的计算机”。

结果,FxRobot 无法实际单击该按钮。您可以看到鼠标在移动,但结果没有发生任何事情。

如上所述更新设置、重新启动 Eclipse 并重新运行测试允许测试实际单击按钮,然后按预期触发事件。

于 2020-03-02T15:41:37.020 回答