<small id='Z4H1l'></small><noframes id='Z4H1l'>

    • <bdo id='Z4H1l'></bdo><ul id='Z4H1l'></ul>

      <legend id='Z4H1l'><style id='Z4H1l'><dir id='Z4H1l'><q id='Z4H1l'></q></dir></style></legend>
        <tfoot id='Z4H1l'></tfoot>

      1. <i id='Z4H1l'><tr id='Z4H1l'><dt id='Z4H1l'><q id='Z4H1l'><span id='Z4H1l'><b id='Z4H1l'><form id='Z4H1l'><ins id='Z4H1l'></ins><ul id='Z4H1l'></ul><sub id='Z4H1l'></sub></form><legend id='Z4H1l'></legend><bdo id='Z4H1l'><pre id='Z4H1l'><center id='Z4H1l'></center></pre></bdo></b><th id='Z4H1l'></th></span></q></dt></tr></i><div id='Z4H1l'><tfoot id='Z4H1l'></tfoot><dl id='Z4H1l'><fieldset id='Z4H1l'></fieldset></dl></div>
      2. 你如何模拟 JavaFX 工具包初始化?

        时间:2023-09-25
        <legend id='Z10FK'><style id='Z10FK'><dir id='Z10FK'><q id='Z10FK'></q></dir></style></legend>

        <small id='Z10FK'></small><noframes id='Z10FK'>

        • <i id='Z10FK'><tr id='Z10FK'><dt id='Z10FK'><q id='Z10FK'><span id='Z10FK'><b id='Z10FK'><form id='Z10FK'><ins id='Z10FK'></ins><ul id='Z10FK'></ul><sub id='Z10FK'></sub></form><legend id='Z10FK'></legend><bdo id='Z10FK'><pre id='Z10FK'><center id='Z10FK'></center></pre></bdo></b><th id='Z10FK'></th></span></q></dt></tr></i><div id='Z10FK'><tfoot id='Z10FK'></tfoot><dl id='Z10FK'><fieldset id='Z10FK'></fieldset></dl></div>
              <tbody id='Z10FK'></tbody>
            <tfoot id='Z10FK'></tfoot>

              • <bdo id='Z10FK'></bdo><ul id='Z10FK'></ul>

                  本文介绍了你如何模拟 JavaFX 工具包初始化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

                  问题描述

                  [序言:抱歉,这里有很多代码,其中一些可能与这个问题无关,而一些理解问题所必需的代码可能会丢失;请发表评论,我会相应地编辑问题.]

                  [preamble: apologies, there is a lot of code here, and some of it may not be relevant to this question while some code which is necessary to understand the problem may be missing; please comment, and I will edit the question accordingly.]

                  环境:Ubuntu 14.10 x86_64;甲骨文 JDK 1.8u25.单元测试库是TestNG,版本6.8.13;Mockito 是 1.10.17 版本.

                  Environment: Ubuntu 14.10 x86_64; Oracle JDK 1.8u25. Unit testing library is TestNG, version 6.8.13; Mockito is version 1.10.17.

                  在我的 GUI 应用程序中,JavaFX 所谓的控制器"是相当被动的,因为这个控制器"(我称之为显示器")真正做的唯一事情就是发送事件.

                  In my GUI application, what JavaFX calls a "controller" is pretty passive, in the sense that the only thing that this "controller" (which I call a "display") really does is send events.

                  现在,当接收到需要更新 GUI 的事件时,它是另一个类,我称之为视图,它负责更新 GUI.简而言之:

                  Now, when an event is received which requires a GUI update, it is another class, which I call a view, which is responsible for updating the GUI. In short:

                  显示 -> 演示者 -> 视图 -> 显示

                  display -> presenter -> view -> display

                  我对其中两个进行了单元测试:

                  I have unit tests for two of these:

                  • 显示 -> 演示者;
                  • 演示者 -> 视图.

                  所以,我在这方面几乎涵盖了(优势在于我可以更改显示,这就是我这样做的原因).

                  So, I am pretty much covered on this front (with the advantage that I can change the display, which is why I'm doing it that way).

                  但现在我尝试测试视图 -> 显示"部分;我是 SOL.

                  But now I try and test the "view -> display" part; and I am SOL.

                  作为说明,这里是视图类:

                  As an illustration, here is the view class:

                  @NonFinalForTesting
                  public class JavafxTreeTabView
                      extends JavafxView<TreeTabPresenter, TreeTabDisplay>
                      implements TreeTabView
                  {
                      private final BackgroundTaskRunner taskRunner;
                  
                      public JavafxTreeTabView(final BackgroundTaskRunner taskRunner)
                          throws IOException
                      {
                          super("/tabs/treeTab.fxml");
                          this.taskRunner = taskRunner;
                      }
                  
                      JavafxTreeTabView(final BackgroundTaskRunner taskRunner,
                          final Node node, final TreeTabDisplay display)
                      {
                          super(node, display);
                          this.taskRunner = taskRunner;
                      }
                  
                  
                      @Override
                      public void loadTree(final ParseNode rootNode)
                      {
                          taskRunner.compute(() -> buildTree(rootNode), value -> {
                              display.parseTree.setRoot(value);
                              display.treeExpand.setDisable(false);
                          });
                      }
                  
                      @Override
                      public void loadText(final InputBuffer buffer)
                      {
                          final String text = buffer.extract(0, buffer.length());
                          display.inputText.getChildren().setAll(new Text(text));
                      }
                  
                      @VisibleForTesting
                      TreeItem<ParseNode> buildTree(final ParseNode root)
                      {
                          return buildTree(root, false);
                      }
                  
                      private TreeItem<ParseNode> buildTree(final ParseNode root,
                          final boolean expanded)
                      {
                          final TreeItem<ParseNode> ret = new TreeItem<>(root);
                  
                          addChildren(ret, root, expanded);
                  
                          return ret;
                      }
                  
                      private void addChildren(final TreeItem<ParseNode> item,
                          final ParseNode parent, final boolean expanded)
                      {
                          TreeItem<ParseNode> childItem;
                          final List<TreeItem<ParseNode>> childrenItems
                              = FXCollections.observableArrayList();
                  
                          for (final ParseNode node: parent.getChildren()) {
                              childItem = new TreeItem<>(node);
                              addChildren(childItem, node, expanded);
                              childrenItems.add(childItem);
                          }
                  
                          item.getChildren().setAll(childrenItems);
                          item.setExpanded(expanded);
                      }
                  }
                  

                  匹配的显示类是这样的:

                  The matching display class is this:

                  public class TreeTabDisplay
                      extends JavafxDisplay<TreeTabPresenter>
                  {
                      @FXML
                      protected Button treeExpand;
                  
                      @FXML
                      protected TreeView<ParseNode> parseTree;
                  
                      @FXML
                      protected TextFlow inputText;
                  
                      @Override
                      public void init()
                      {
                          parseTree.setCellFactory(param -> new ParseNodeCell(presenter));
                      }
                  
                      @FXML
                      void expandParseTreeEvent(final Event event)
                      {
                      }
                  
                      private static final class ParseNodeCell
                          extends TreeCell<ParseNode>
                      {
                          private ParseNodeCell(final TreeTabPresenter presenter)
                          {
                              setEditable(false);
                              selectedProperty().addListener(new ChangeListener<Boolean>()
                              {
                                  @Override
                                  public void changed(
                                      final ObservableValue<? extends Boolean> observable,
                                      final Boolean oldValue, final Boolean newValue)
                                  {
                                      if (!newValue)
                                          return;
                                      final ParseNode node = getItem();
                                      if (node != null)
                                          presenter.parseNodeShowEvent(node);
                                  }
                              });
                          }
                  
                          @Override
                          protected void updateItem(final ParseNode item, final boolean empty)
                          {
                              super.updateItem(item, empty);
                              setText(empty ? null : String.format("%s (%s)", item.getRuleName(),
                                  item.isSuccess() ? "SUCCESS" : "FAILURE"));
                          }
                      }
                  }
                  

                  这是我的测试文件:

                  public final class JavafxTreeTabViewTest
                  {
                      private final Node node = mock(Node.class);
                      private final BackgroundTaskRunner taskRunner = new BackgroundTaskRunner(
                          MoreExecutors.newDirectExecutorService(), Runnable::run
                      );
                      private JavafxTreeTabView view;
                      private TreeTabDisplay display;
                  
                      @BeforeMethod
                      public void init()
                          throws IOException
                      {
                          display = new TreeTabDisplay();
                          view = spy(new JavafxTreeTabView(taskRunner, node, display));
                      }
                  
                      @Test
                      public void loadTreeTest()
                      {
                          final ParseNode rootNode = mock(ParseNode.class);
                          final TreeItem<ParseNode> item = mock(TreeItem.class);
                  
                          doReturn(item).when(view).buildTree(same(rootNode));
                  
                          display.parseTree = mock(TreeView.class);
                          display.treeExpand = mock(Button.class);
                  
                          view.loadTree(rootNode);
                  
                  
                          verify(display.parseTree).setRoot(same(item));
                          verify(display.treeExpand).setDisable(false);
                      }
                  }
                  

                  我希望它能够工作......但它没有.然而相距甚远"我试图避开平台代码,即使上面的测试类也因这个异常而失败:

                  I expected it to work... Except that it doesn't. However "far apart" I try to steer away from the platform code, even the test class above fails with this exception:

                  java.lang.ExceptionInInitializerError
                      at sun.reflect.GeneratedSerializationConstructorAccessor5.newInstance(Unknown Source)
                      at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
                      at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45)
                      at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
                      at org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:14)
                      at org.mockito.internal.creation.cglib.ClassImposterizer.createProxy(ClassImposterizer.java:143)
                      at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:58)
                      at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49)
                      at org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24)
                      at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33)
                      at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59)
                      at org.mockito.Mockito.mock(Mockito.java:1285)
                      at org.mockito.Mockito.mock(Mockito.java:1163)
                      at com.github.fge.grappa.debugger.csvtrace.tabs.JavafxTreeTabViewTest.loadTreeTest(JavafxTreeTabViewTest.java:46)
                      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
                      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                      at java.lang.reflect.Method.invoke(Method.java:483)
                      at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
                      at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
                      at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
                      at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
                      at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
                      at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
                      at org.testng.TestRunner.privateRun(TestRunner.java:767)
                      at org.testng.TestRunner.run(TestRunner.java:617)
                      at org.testng.SuiteRunner.runTest(SuiteRunner.java:348)
                      at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:343)
                      at org.testng.SuiteRunner.privateRun(SuiteRunner.java:305)
                      at org.testng.SuiteRunner.run(SuiteRunner.java:254)
                      at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
                      at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
                      at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
                      at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
                      at org.testng.TestNG.run(TestNG.java:1057)
                      at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
                      at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
                      at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
                      at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:125)
                      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
                      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                      at java.lang.reflect.Method.invoke(Method.java:483)
                      at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
                  Caused by: java.lang.IllegalStateException: Toolkit not initialized
                      at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:270)
                      at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:265)
                      at com.sun.javafx.application.PlatformImpl.setPlatformUserAgentStylesheet(PlatformImpl.java:540)
                      at com.sun.javafx.application.PlatformImpl.setDefaultPlatformUserAgentStylesheet(PlatformImpl.java:502)
                      at javafx.scene.control.Control.<clinit>(Control.java:87)
                      ... 44 more
                  

                  那么,简而言之,我该如何防止上述异常的发生呢?我原以为将小部件模拟掉就足够了,但显然不是:/看起来我需要模拟整个平台上下文"(因为没有更好的词),但我不知道怎么做.

                  So, in short, how do I prevent the exception above from happening? I'd have thought that mocking the widgets away would have been enough, but apparently not :/ It looks like I need to mock the whole "platform context" (for lack of a better word for it) but I have no idea how.

                  推荐答案

                  好吧,第一件事:我从来没有用过一次 Mockito.但我很好奇,所以我花了几个小时来解决这个问题,我想还有很多需要改进的地方.

                  Ok, first things first: I never used Mockito once in a life. But I was curious, so I spent several hours to figure this out and I guess there is much to improve.

                  所以要让这个工作,我们需要:

                  So to get this working, we need:

                  1. 上述(@jewelsea)JUnit 线程规则.
                  2. 一个自定义的 MockMaker 实现,包装了默认的 CglibMockMaker.
                  3. 将所有东西连接在一起.
                  1. The aforementioned (by @jewelsea) JUnit Threading Rule.
                  2. A custom MockMaker implementation, wrapping the default CglibMockMaker.
                  3. Wire the things together.

                  所以 1+2 是这样的:

                  So 1+2 is this:

                  public class JavaFXMockMaker implements MockMaker {
                  
                      private final MockMaker wrapped = new CglibMockMaker();
                      private boolean jfxIsSetup;
                  
                      private void doOnJavaFXThread(Runnable pRun) throws RuntimeException {
                          if (!jfxIsSetup) {
                              setupJavaFX();
                              jfxIsSetup = true;
                          }
                          final CountDownLatch countDownLatch = new CountDownLatch(1);
                          Platform.runLater(() -> {
                              pRun.run();
                              countDownLatch.countDown();
                          });
                  
                          try {
                              countDownLatch.await();
                          } catch (InterruptedException e) {
                              throw new RuntimeException(e);
                          }
                      }
                  
                      protected void setupJavaFX() throws RuntimeException {
                          final CountDownLatch latch = new CountDownLatch(1);
                          SwingUtilities.invokeLater(() -> {
                              new JFXPanel(); // initializes JavaFX environment
                              latch.countDown();
                          });
                  
                          try {
                              latch.await();
                          } catch (InterruptedException e) {
                              throw new RuntimeException(e);
                          }
                      }
                  
                      @Override
                      public <T> T createMock(MockCreationSettings<T> settings, MockHandler handler) {
                          AtomicReference<T> result = new AtomicReference<>();
                          Runnable run = () -> result.set(wrapped.createMock(settings, handler));
                          doOnJavaFXThread(run);
                          return result.get();
                      }
                  
                      @Override
                      public MockHandler getHandler(Object mock) {
                          AtomicReference<MockHandler> result = new AtomicReference<>();
                          Runnable run = () -> result.set(wrapped.getHandler(mock));
                          doOnJavaFXThread(run);
                          return result.get();
                      }
                  
                      @Override
                      public void resetMock(Object mock, MockHandler newHandler, @SuppressWarnings("rawtypes") MockCreationSettings settings) {
                          Runnable run = () -> wrapped.resetMock(mock, newHandler, settings); 
                          doOnJavaFXThread(run);
                      }
                  
                  }
                  

                  数字 3 只是按照手册:

                  Number 3 is just following the manual:

                  1. 复制我们的 MockMaker 的完全限定类名,例如.org.awesome.mockito.JavaFXMockMaker.
                  2. 创建一个文件mockito-extensions/org.mockito.plugins.MockMaker".该文件的内容正好是带有限定名称的一行.

                  快乐的测试和感谢 Andy Till 的线程规则.

                  Happy testing & kudos to Andy Till for his threading rule.

                  警告:这种实现对 MockMaker 使用 CglibMockMaker 可能不是你想要的(见 JavaDocs).

                  Warning: This implementation kind of hard-codes the MockMaker to use the CglibMockMaker which might not be be what you want in every case (see the JavaDocs).

                  这篇关于你如何模拟 JavaFX 工具包初始化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!

                  上一篇:在同一个模拟上使用多个 ArgumentMatchers 下一篇:为 Factory 类创建的对象注入 Mocks

                  相关文章

                  最新文章

                  <small id='ZznuK'></small><noframes id='ZznuK'>

                1. <tfoot id='ZznuK'></tfoot>

                2. <i id='ZznuK'><tr id='ZznuK'><dt id='ZznuK'><q id='ZznuK'><span id='ZznuK'><b id='ZznuK'><form id='ZznuK'><ins id='ZznuK'></ins><ul id='ZznuK'></ul><sub id='ZznuK'></sub></form><legend id='ZznuK'></legend><bdo id='ZznuK'><pre id='ZznuK'><center id='ZznuK'></center></pre></bdo></b><th id='ZznuK'></th></span></q></dt></tr></i><div id='ZznuK'><tfoot id='ZznuK'></tfoot><dl id='ZznuK'><fieldset id='ZznuK'></fieldset></dl></div>

                      <legend id='ZznuK'><style id='ZznuK'><dir id='ZznuK'><q id='ZznuK'></q></dir></style></legend>
                        <bdo id='ZznuK'></bdo><ul id='ZznuK'></ul>