在JUnit测试中模拟按键

时间:2017-11-16 18:25:23

标签: java swing junit

我完全陷入了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的text属性也没有改变......

这是我现在的方法:

@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());
    });


  }

3 个答案:

答案 0 :(得分: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技巧或自定义运行器在运行挥杆测试时自动更改为EDT。

<强>更新

我很好奇,并试图找到一个现有的@Rule,它将@Before@Test@After代码放到了EDT上,但是我的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());
    }
}

使用jdk1.8.0_121

在MacOS上测试

答案 1 :(得分:0)

哟,我猜你有两个选择

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

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

  • 制作UI元素的屏幕截图,并将其放入应用的测试数据文件夹中 使用sikuli + JUnit
  • 编写简单测试,为您设置按钮图片的路径(例如)
  • 并撰写动作,移动,点击或实际需要的内容。 非常简单,看起来像

    按钮按钮=新按钮(&#34;测试文件夹/ p​​ic1.jpg&#34;);

    button.click();

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

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

答案 2 :(得分:0)

最近,我不得不测试一个自定义的KeyAdapter,并创建了一个自定义的JTextField来分发键事件。下面是我使用的一部分代码:

implementation 'mysql:mysql-connector-java:5.1.45'