在JUnit测试中模拟按键

问题描述 投票:2回答:3

我完全陷入了java测试;它是关于通过测试方法将字符'a'发送到JFrame组件的JTextField。

JFrame类实现KeyListener接口,因此覆盖KeyPressed,KeyTyped和KeyReleased。与此同时,我将JTextField的所有keypressed转移到JFrame;我在JFrame构造函数中有:

JTextField txf_version = new JTextField();
txf_version.addKeyListener(this);

我想测试这种行为,然后模拟JTextField中字符类型的操作。

我所有的尝试都失败了我尝试使用java.awt.Robot类,如下所示:hava a look at this other post in stack overflow,但我得到一个奇怪的行为:调用

robot.keyPress(KeyEvent.VK_A);

直接在我的IDE中显示字符,而不是在虚拟JFrame中显示!尝试使用requestFocus()或requestFocusInWindow()无效。

我也尝试过使用KeyEvents:

KeyEvent key = new KeyEvent(bookWindow.txf_version, KeyEvent.KEY_PRESSED, System
        .currentTimeMillis(), 0, KeyEvent.VK_UNDEFINED, 'a');
bookWindow.txf_version.dispatchEvent(key);

但同样,textfield的文本属性没有改变......

这是我现在的方法:

@Test
void testBtnSaveChangesBecomesRedWhenVersionChanged() throws AWTException,
      InterruptedException, NoSuchFieldException, IllegalAccessException {
  initTest();

  KeyEvent key = new KeyEvent(bookWindow.txf_version, KeyEvent.KEY_PRESSED, System
        .currentTimeMillis(), 0, KeyEvent.VK_UNDEFINED, 'a');
  bookWindow.txf_version.dispatchEvent(key);

  System.out.println("dans txf_version : " + bookWindow.txf_version.getText
        ());

  assertEquals(Color.RED, bookWindow.getBtnSaveChangesForegroundColor());


}

我可以通过在JFrame的子类中编写main()方法来查看实际行为,但我认为知道如何模拟swing组件测试的键是很有用的。

谢谢

编辑:我根据AJNeufeld的答案更改了我的测试代码,但它仍然无效。这是我的测试代码:

@Test
void testBtnSaveChangesBecomesRedWhenVersionChanged() throws AWTException,
      InterruptedException, NoSuchFieldException, IllegalAccessException,
      InvocationTargetException {
//bookEditor2 & bookWindow
SwingUtilities.invokeAndWait(() -> {
  bookWindow = new BookWindow();
  VectorPerso two = new VectorPerso();
  two.add(le_livre_de_la_jungle);
  two.add(elogeMaths);
  bookWindow.setTableDatas(two);
  bookWindow.table.setRowSelectionInterval(1, 1);
  bookWindow.txf_version.requestFocusInWindow();
  KeyEvent key = new KeyEvent(bookWindow.txf_version, KeyEvent.KEY_TYPED, System
          .currentTimeMillis(), 0, KeyEvent.VK_UNDEFINED, 'a');
  bookWindow.txf_version.dispatchEvent(key);
  try {
    Thread.sleep(1000);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
  System.out.println("dans txf_version : " + bookWindow.txf_version.getText
          ());

  assertEquals(Color.RED, bookWindow.getBtnSaveChangesForegroundColor());
});


}

plintln行在控制台中生成一个文本:“dans txf_version:0”,表示密钥未发送到txf_version。

编辑2:

新尝试:

@Test
  void testBtnSaveChangesBecomesRedWhenVersionChanged() throws AWTException,
          InterruptedException, NoSuchFieldException, IllegalAccessException,
          InvocationTargetException {
    //bookEditor2 & bookWindow
    SwingUtilities.invokeAndWait(() -> {
      bookWindow = new BookWindow();
      VectorPerso two = new VectorPerso();
      two.add(le_livre_de_la_jungle);
      two.add(elogeMaths);
      bookWindow.setTableDatas(two);
      bookWindow.table.setRowSelectionInterval(1, 1);
      bookWindow.txf_version.requestFocusInWindow();
      KeyEvent key = new KeyEvent(bookWindow.txf_version, KeyEvent.KEY_TYPED, System

              .currentTimeMillis(), 0, KeyEvent.VK_UNDEFINED, 'a');
      bookWindow.txf_version.dispatchEvent(key);
    });
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }

    SwingUtilities.invokeAndWait(() -> {
      System.out.println("dans txf_version : " + bookWindow.txf_version.getText
              ());

      assertEquals(Color.RED, bookWindow.getBtnSaveChangesForegroundColor());
    });


  }
java swing junit
3个回答
1
投票

我认为你做了一些错事,但没有一个完整的例子,很难说。

首先,JTextField并不真正关心KEY_PRESSED事件。它关注KEY_TYPED事件。

其次,Swing处理Event Dispatching Thread(EDT)上的事件,它不一定是JUnit将要运行的线程。当你不在美国东部时,你真的不应该改变事情。我不确定eventDispatch()是否会切换到EDT。它可能。但它也可能使用invokeLater()来做,在这种情况下执行会立即传递给assertEquals(),但失败了,因为事件处理还没有发生。

这是一个最小的,完整的,可验证的示例,它显示了一个发送的按键,它改变了按钮颜色,还有一个JUnit测试用例,它检查并传递:

一,被测代码:

public class SwingUnitTesting extends JFrame {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(SwingUnitTesting::new);
    }

    JTextField tf = new JTextField();
    JButton btn = new JButton("Test Button");

    SwingUnitTesting() {
        add(tf, BorderLayout.PAGE_END);
        add(btn, BorderLayout.PAGE_START);

        tf.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                btn.setForeground(Color.RED);
            }
        });

        setSize(200, 80);
        setLocationByPlatform(true);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setVisible(true);
    }
}

单元测试:

public class SwingUnitTestingTest {

    SwingUnitTesting sut;

    @Before
    public void setUp() throws Exception {
        SwingUtilities.invokeAndWait(() -> {
            sut = new SwingUnitTesting();
        });
    }

    @Test
    public void btnNotRedBeforeKeypress() throws InvocationTargetException, InterruptedException {
        SwingUtilities.invokeAndWait(() -> {
            assertNotEquals(Color.RED, sut.btn.getForeground());
        });
    }

    @Test
    public void btnRedAfterKeypress() throws InvocationTargetException, InterruptedException {
        SwingUtilities.invokeAndWait(() -> {
            sut.tf.requestFocusInWindow();
            sut.tf.dispatchEvent(new KeyEvent(sut.tf,
                    KeyEvent.KEY_TYPED, System.currentTimeMillis(), 0,
                    KeyEvent.VK_UNDEFINED, 'A'));
            assertEquals(Color.RED, sut.btn.getForeground());
        });
    }
}

您可以使用一些JUnit @Rule技巧或自定义运行器在运行swing测试时自动更改为EDT。


更新:

我很好奇,并试图找到一个现有的@Rule,它将@Before@Test@After代码放到了美国东部时间,但是我的Google-fu让我失望了;我知道我以前见过它,但我找不到它。最后,我创建了自己的:

public class EDTRule implements TestRule {

    @Override
    public Statement apply(Statement stmt, Description dscr) {
        return new Statement() {
            private Throwable ex;

            @Override
            public void evaluate() throws Throwable {
                SwingUtilities.invokeAndWait(() -> {
                    try {
                        stmt.evaluate();
                    } catch (Throwable t) {
                        ex = t;
                    }
                });
                if (ex != null) {
                    throw ex;
                }
            }
        };
    }
}

使用此规则,JUnit测试变得更简单:

public class SwingUnitTestingTest {

    @Rule
    public TestRule edt = new EDTRule();

    SwingUnitTesting sut;

    @Before
    public void setUp() throws Exception {
        sut = new SwingUnitTesting();
    }

    @Test
    public void btnNotRedBeforeKeypress() {
        assertNotEquals(Color.RED, sut.btn.getForeground());
    }

    @Test
    public void btnRedAfterKeypress() {
        sut.tf.requestFocusInWindow();
        sut.tf.dispatchEvent(
                new KeyEvent(sut.tf, KeyEvent.KEY_TYPED, System.currentTimeMillis(), 0, KeyEvent.VK_UNDEFINED, 'A'));
        assertEquals(Color.RED, sut.btn.getForeground());
    }
}

在MacOS上测试,使用jdk1.8.0_121


0
投票

哟,我想你有两个选择

1)仍然需要使用SWING找到解决方案(但在这种情况下,我没有任何经验和任何想法如何帮助你)。

2)使用Sikulli java框架测试桌面应用程序。你可以添加dependency然后

  • 制作UI元素的屏幕截图,并将它们放入应用程序的测试数据文件夹中使用sikuli + JUnit
  • 写一个简单的测试,你设置一个按钮pic的路径(例如)
  • 并写下动作,移动,点击或实际需要的内容。非常简单,看起来像 按钮=新按钮(“test-folder / pic1.jpg”); button.click();

运行后,您将看到,光标在按钮上移动,然后单击它。

有关更多详细信息,请在Web中查找有关Sikuli + Java的示例。


0
投票

最近我不得不测试一个自定义的KeyAdapter,我创建了一个自定义的JTextField来发送关键事件。我使用的一段代码如下:

public class ProcessKeyOnTextFieldTest {

    @Test
    public void pressKeyTest() throws Exception {
        JTextFieldWithTypedKeySupport textField = new JTextFieldWithTypedKeySupport();

        textField.pressKey('a');
        textField.pressKey('b');

        assertEquals("ab", textField.getText());
    }

    class JTextFieldWithTypedKeySupport extends JTextField {

        int timestamp;

        void pressKey(char key) throws InvocationTargetException, InterruptedException {
            SwingUtilities.invokeAndWait(() -> super.processKeyEvent(createEvent(key)));
        }

        KeyEvent createEvent(char keyChar) {
            return new KeyEvent(this, KeyEvent.KEY_TYPED, timestamp++, 0, KeyEvent.VK_UNDEFINED, keyChar);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.