当前位置: 首页 > 知识库问答 >
问题:

应用与应用测试:不同的事件调度?

农飞星
2023-03-14

目前我正在研究文本字段和默认/取消按钮的问题。在使用TestFX测试假定的修复时,我遇到了事件调度方面的差异(?)这使得测试在应用程序运行时失败。

下面是一个非常简化的版本:

  • 只是一个简单的用户界面,由一个框中的文本字段组成,用于应用程序/测试

修复程序的关键部分是创建actionEvent,将textField同时作为源和目标(以防止在调度期间将事件复制到新实例中):

ActionEvent action = new ActionEvent(field, field);

运行应用程序时,这似乎足以让它工作。运行测试时,失败-将事件复制到另一个实例,以便使用的事件与分派中传递的事件是不同的实例(仅在调试期间可见)。无法确定发生这种情况的确切地点/原因。

问题是:这种差异是预期的吗?如果是,为什么/在哪里?或者我做错了什么(概率远远不是零)?

来繁殖

  • 运行app,按a:注意说明已触发actionEvent已消耗的日志
  • 运行test,注意日志说明触发的actionEvent没有被消耗

代码:

public class ActionApp extends Application {

    // create a simple ui - static because must be same for ActionTest
    public static Parent createContent() {
        TextField field = new TextField();
        // some handler to fire an actionEvent
        field.addEventHandler(KeyEvent.KEY_PRESSED, e -> {
            if (e.getCode() == KeyCode.A) {
                ActionEvent action = new ActionEvent(field, field);
                field.fireEvent(action);
                LOG.info("action/consumed? " + action + action.isConsumed());
            }
        });
        // another handler to consume the fired action
        field.addEventHandler(ActionEvent.ACTION, e -> {
            e.consume();
            LOG.info("action received " + e + e.isConsumed());
        });

        VBox actionUI = new VBox(field);
        return actionUI;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        stage.setTitle(FXUtils.version());
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(ActionApp.class.getName());

}

测试:

public class ActionTest extends  ApplicationTest {

    /**
     * Does not really test anything, just to see the output.
     */
    @Test
    public void testConsumeA() {
        // sanity: focused to receive the key
        verifyThat(".text-field", NodeMatchers.isFocused());
        press(KeyCode.A);
    }

    @Override
    public void start(Stage stage) {
        Parent root = ActionApp.createContent();
        Scene scene = new Scene(root, 100, 100);
        stage.setScene(scene);
        stage.show();
    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(ActionTest.class.getName());
}

我的环境是从2018年10月在win10上的fx11和TestFX。仅供参考:在testFX中打开了一个问题

共有1个答案

漆雕修能
2023-03-14

区别在于TestFx为EventType注入了一个eventFilter。在存储所有激发事件的舞台上设置ROOT。黑客就是把过滤器取下来,弄得脏兮兮的,比如:

public static void stopStoringFiredEvents() {
    FxToolkitContext context = FxToolkit.toolkitContext();
    // reflectively access the private field of the context
    FiredEvents fired =(FiredEvents) FXUtils.invokeGetFieldValue(FxToolkitContext.class, context, "firedEvents");
    // stop recording
    fired.stopStoringFiredEvents();
}

/**
 * Updated hack, now reaaally dirty: need to manually clear the handler map :(
 */
public static void stopStoringFiredEvents(Stage stage) {
    // remove the event-logging filter
    stopStoringFiredEvents();
    // really cleanup: 
    // removing the filter only nulls the eventHandler in CompositeEventHandler
    // but does not remove the Composite from EventHandlerManager.handlerMap
    // as a result, handlerManager.dispatchCapturingEvent runs into the fixForSource
    // block which copies the event even though there is no filter
    WindowEventDispatcher windowDispatcher = (WindowEventDispatcher) stage.getEventDispatcher();
    EventHandlerManager manager = windowDispatcher.getEventHandlerManager();
    Map<?, ?> handlerMap = (Map<?, ?>) FXUtils.invokeGetFieldValue(EventHandlerManager.class, manager, "eventHandlerMap");
    handlerMap.clear();
}

虽然这种方法绕过了这个特定的上下文,但在一般情况下并没有可靠的帮助:只要父层次结构中的任何地方有一个eventFilter(与激发的事件具有相同或超级eventType),就会发生同样的情况。根本原因似乎是,在为eventFilters分派事件时,事件分派会创建新的事件实例(通过event.copyFor)。因此,动作处理程序中使用的事件实例与fire发出的实例不同。

更新:

  • 注意到仅仅移除firedEvents过滤器并没有帮助(不知道为什么它看起来像几天前那样……):一旦有了一个过滤器,事件就会被永久地分派到其包含的处理程序,即使它稍后被清空
  • 提出异议
 类似资料:
  • 无论何时,您的Electron应用程序没有按照您设想的方式运行,一组调试工具也许可以帮助您找到代码的错误,性能瓶颈,或者优化的机会。 Application Debugging Whenever your Electron application is not behaving the way you wanted it to, an array of debugging tools might

  • 无论何时,您的Electron应用程序没有按照您设想的方式运行,一组调试工具也许可以帮助您找到代码的错误,性能瓶颈,或者优化的机会。 渲染进程 最广泛使用来调试指定渲染进程的工具是Chromium的开发者工具集。 它可以获取到所有的渲染进程,包括BrowserWindow的实例,BrowserView以及WebView。 您可以通过编程的方式在BrowserWindow的webContents中调

  • 我有一个java应用程序(没有Spring)。此应用程序的副本在另一台服务器上工作,另一个数据库实例。数据库表“设置”有属性主Y或N(用于副本)。在主上的任何操作后,我向kafka发送消息,kafka向副本发送操作,并使用db更新操作。测试此过程的整个周期有什么想法吗? 我使用测试容器来获取kafka和数据库。但是我不知道如何在测试容器实例中启动我的db应用程序。

  • 前面几章中讲过的Hello猫咪、打地鼠以及其他应用都是些非常小的软件项目,并不需要用引入软件工程的概念。工程的概念借用自其他行业,意为设计并建造,教程中的应用就像是用预制件拼装起来的房屋模型,而软件工程才是设计并建造真正用来居住的房子。这个例子虽然稍显夸张,但一般来讲,某些极其复杂的建造过程,的确需要大量的前期构思、规划以及技术分析,这些过程都可以归结为工程。 但凡接手过一个相对复杂的项目,你就会

  • null 警告:与依赖项“com.android.support:support-annotations”冲突。应用程序(22.0.0)和测试应用程序(21.0.3)的解析版本不同。 Gradle本身更宽容,但Android工作室,就没那么宽容了。 我没有用21.0.3声明的依赖项...是不是其中一个依赖库使用21.0.3而谷歌忘了用批处理的其余部分更新它? null null null

  • jd.offAppHide(function callback) 取消监听小程序切后台事件 (基础库1.10.8开始支持) 参数 function callback 小程序切后台事件的回调函数 调用示例 jd.offAppHide(function(e){ console.log("监听offAppHide,",e); }) jd.offAppShow(function callback