在我的程序中,我正在测试一个按钮,单击该按钮会在应用程序中抛出一个JOptionPane窗口。
然而,当弹出此窗口时,它希望用户单击“确定”,这意味着除非手动关闭窗口,否则测试无法继续。
我希望能够在我的测试中出现时以编程方式关闭此窗口,或者阻止这些JOptionPane窗口完全弹出以进行此测试。
答案 0 :(得分:2)
在这种情况下,我通常做的是确保UI不会出现在我的测试中。只是用一些代码来说明这一点。让我们说对话框是在Action
public class ActionWithUI extends AbstractAction{
@Override
public void actionPerformed( ActionEvent e ){
//... do some stuff
int result = JOptionPane.show... //show the dialog
//do some other stuff based on the result of the JOptionPane
}
}
然后我会重构我的代码,以便JOptionPane
的显示在它自己的单独方法中。
public class ActionWithUI extends AbstractAction{
@Override
public void actionPerformed( ActionEvent e ){
//... do some stuff
int result = askUserForInput();
//do some other stuff based on the result of the JOptionPane
}
int askUserForInput(){
return JOptionPane.show...
}
}
现在在我的测试中,我可以测试该操作的自定义版本,其中我覆盖askUserForInput
方法并返回"确定" (或"取消",...)选项。这将避免我的测试中任何聪明的技巧,并保持我的代码可读。
我有时使用的另一种方法是不直接调用JOptionPane.show
,而是确保我的类在其构造函数中接受用于显示此类对话框的委托类。在我的测试中,我可以插入一个模拟而不是真正的类,并拦截对UI的调用。
当然,这两种方法实际上都没有测试JOptionPane
是否正确显示。但看到这是一个JDK方法,我真的觉得不需要测试它。并不是说我绕过了一些业务逻辑。我刚刚摆脱了JOptionPane.show
电话。
如果这些都不是选项,我通常会使用附加到DefaultKeyboardFocusManager
的监听器。当具有焦点的组件发生变化时,我会看到它是JOptionPane
(使用Swing层次结构)并将其处理掉。结果很好,但仍然不是100%可靠。因此(当然对于新代码而言),我试图坚持以前概述的两种方法之一
答案 1 :(得分:1)
有两种基本方法可以解决这个问题。两者都要求您能够找到按钮。
这将需要能够使用第二个Thread
找到窗口/对话框并走它的容器来找到按钮......
取决于您的测试设置方式取决于您可能需要经历多少额外工作。 UI应该在Event Dispatching Thread中运行,如果您的测试在同一个线程中运行,那么您将需要使用单独的Thread
,因为JOptionPane
将阻止EDT(以特殊方式),使代码无法运行,直到选项窗格关闭。
如果您的测试已在单独的Thread
中运行,那么您可以获得更多功能......
这是一个非常简单的例子。它在EDT的上下文中初始化JOptionPane
,但是在主线程中运行的方法可以找到并执行" OK"消息对话框的按钮。
import java.awt.Button;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Window;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class FindButton {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JOptionPane.showMessageDialog(null, "This is message dialog", "Message", JOptionPane.INFORMATION_MESSAGE);
}
});
JDialog frame = waitForDialog("Message");
System.out.println("Found window " + frame);
if (frame != null) {
final JButton btn = getButton(frame, "OK");
System.out.println("Found button " + btn);
if (btn != null) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
btn.doClick();
}
});
}
}
}
public static JDialog waitForDialog(String title) {
JDialog win = null;
do {
for (Window window : Frame.getWindows()) {
if (window instanceof JDialog) {
JDialog dialog = (JDialog) window;
System.out.println(dialog.getTitle());
if (title.equals(dialog.getTitle())) {
win = dialog;
break;
}
}
}
if (win == null) {
try {
Thread.sleep(250);
} catch (InterruptedException ex) {
break;
}
}
} while (win == null);
return win;
}
public static JButton getButton(Container container, String text) {
JButton btn = null;
List<Container> children = new ArrayList<Container>(25);
for (Component child : container.getComponents()) {
System.out.println(child);
if (child instanceof JButton) {
JButton button = (JButton) child;
if (text.equals(button.getText())) {
btn = button;
break;
}
} else if (child instanceof Container) {
children.add((Container) child);
}
}
if (btn == null) {
for (Container cont : children) {
JButton button = getButton(cont, text);
if (button != null) {
btn = button;
break;
}
}
}
return btn;
}
}
此示例使用doClick
的{{1}}方法模拟按钮的单击。您可以使用按钮中的JButton
信息和locationOnScreen
来物理点击按钮。但这似乎更简单。
你也可以看一下Jemmy这是一个很好用的库,旨在让它更容易测试基于Swing(和JavaFX)的应用程序......
答案 2 :(得分:0)
首先,从JDialog
对象创建JOptionPane
。然后,创建一个timer
以运行您想要的时间(例如1分钟),并在完成后处置dialog
。然后,从JOptionPane
对象中检索所选值,确保在计时器处理对话框时考虑未初始化的值。
final JOptionPane pane = new JOptionPane(......., JOptionPane.OK_CANCEL_OPTION);
final JDialog dialog = pane.createDialog(.....);
Timer timer = new Timer(you_time, new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
dialog.dispose();
}
});
timer.start();
dialog.setVisible(true);
dialog.dispose();
Integer choice = (Integer) (pane.getValue() == JOptionPane.UNINITIALIZED_VALUE ? JOptionPane.OK_OPTION : pane.getValue());