Java 在JUnit测试中模拟按键
我完全被困在java测试中;它是关于通过测试方法将字符“a”发送到JFrame组件的JTextField JFrame类实现KeyListener接口,因此覆盖KeyPressed、KeyTyped和KeyRelease。同时,我将JTextField的所有按键转移到JFrame;在JFrame构造函数中,我有:Java 在JUnit测试中模拟按键,java,swing,junit,Java,Swing,Junit,我完全被困在java测试中;它是关于通过测试方法将字符“a”发送到JFrame组件的JTextField JFrame类实现KeyListener接口,因此覆盖KeyPressed、KeyTyped和KeyRelease。同时,我将JTextField的所有按键转移到JFrame;在JFrame构造函数中,我有: JTextField txf_version = new JTextField(); txf_version.addKeyListener(this); 我想测试这个行为,然后在JT
JTextField txf_version = new JTextField();
txf_version.addKeyListener(this);
我想测试这个行为,然后在JTextField中模拟a型角色的动作
我所有的尝试都失败了;我尝试使用java.awt.Robot类,如下所示:,但我得到一个奇怪的行为:调用
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_版本:0”,表示密钥未发送到txf_版本
编辑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());
});
}
哟,我想你有两个选择 1) 仍然需要使用SWING来找到解决方案(但在这种情况下,我没有经验,也不知道如何帮助您) 2) 它使用SikulliJava框架来测试桌面应用程序。您可以添加
- 制作UI元素的屏幕截图,并将它们放入应用程序的测试数据文件夹中 使用sikuli+JUnit
- 编写一个简单的测试,在其中为按钮的pic设置一个路径(例如)
- 写下动作,移动,点击或者你真正需要的东西。 在非常简单的情况下,这将是 按钮按钮=新按钮(“测试文件夹/pic1.jpg”) 按钮。单击()
有关更多详细信息,请在web上查找有关Sikulli+Java的示例。我认为您在做一些错误的事情,但如果没有完整的示例,则很难判断 首先,
JTextField
实际上与按下的键事件无关。它与键入的键
事件有关
其次,Swing在事件调度线程(EDT)上处理事件,它不一定是JUnit要运行的线程。当你不参加EDT时,你真的不应该改变事情。我不确定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());
});
}
}
在运行swing测试时,您可能会使用一些JUnit@Rule
技巧或自定义运行程序来自动更改为EDT
更新:
我感到好奇,并试图找到一个现有的@规则
,它将@放在@之前
,@测试
,以及@之后
代码放在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());
}
}
在MacOS上使用jdk1.8.0_121测试,最近我不得不测试一个定制的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);
}
}
}
你好,谢谢你的回答。我不知道JUnit中的规则,所以我尝试在没有规则的情况下修改您的答案,但仍然存在一个问题。我将所有测试代码放在Swing线程中,但是textField的文本没有更改。请看一下我的编辑。你不能(有效地)在EDT中睡觉。Swing在EDT中处理事件,因此如果您休眠该线程,则不会处理任何内容。相反,您需要如下内容:invokeAndWait(()->{…});Thread.sleep();调用EANDWAIT(()->{…})代码>。您可以根据需要多次调用invokeAndWait
。请看一下我的问题,我已经更新了,但仍然不起作用。它应该可以工作,我真的不明白为什么会有错误。textfield包含其默认值0,即使在注入keyEvent之后,至少是预期要执行此操作的语句。完成!我在JFrame类中进行了搜索,当我在构造函数中添加一些关于窗口的内容时,它确实起了作用:setLocationByPlatform(true)、setLocation(0,0)、setSize(100,50)、setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)和几乎setVisible(true)。无头测试显然不适用于这种方法!再次感谢。谢谢,这是一个有趣的工具sikuli,但我认为该网站似乎已关闭。然而,我更愿意让这个项目无头地测试我的JFrame,让它更简单。