可能重复:
使FEST等待应用程序加载
注意:这个问题与这个问题基本相同。由于这个问题没有答案,我决定将这个例子扩展到一个可运行的SSCE中,并提供一些额外的信息,希望能得到一些帮助。
因此,问题是当所查找的组件可能还不存在时,应该如何处理组件查找。看看这个简单的单标签GUI。
public class MyFrame extends JFrame {
JLabel theLabel;
public MyFrame() {
this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
theLabel = new JLabel();
theLabel.setName("theLabelName");
computeLabelContentOnWorkerThread();
}
private void computeLabelContentOnWorkerThread() {
new SwingWorker<String, Void>() {
@Override
protected String doInBackground() throws Exception {
Thread.sleep(5000);
return "Info from slow database connection";
}
@Override
protected void done() {
try {
theLabel.setText(get());
add(theLabel);
pack();
setVisible(true);
} catch (InterruptedException ignore) {
} catch (ExecutionException ignore) {
}
}
}.execute();
}
}
这个测试用例:
public class TestOfDelayedComponent extends FestSwingJUnitTestCase {
FrameFixture frameWrapper;
@Before
public void onSetUp() {
MyFrame frame = GuiActionRunner.execute(new GuiQuery<MyFrame>() {
protected MyFrame executeInEDT() {
return new MyFrame();
}
});
frameWrapper = new FrameFixture(robot(), frame);
frameWrapper.show();
}
@Test
public void testLabelContent() {
String labelContent = frameWrapper.label("theLabelName").text();
assertTrue(labelContent.equals("Info from slow database connection"));
}
}
会发生什么?标签组件的构造被委托给一个缓慢的工作线程。因此,当GUI出现时,标签不会立即出现。运行测试用例时,标签尚未出现,因此在frameWrapper.label("theLabelName")
执行组件查找时,会引发ComponentLookupException。
问题是如何防止引发此异常如果它是一个顶级组件,我可以执行WindowFinder.findFrame("title").withTimeout(10000)
来获得一个FrameFinder对象,该对象可以查找帧,即使在帧出现之前有延迟。我想要的是类似的东西,但用于其他类型的组件,例如JLabel。
注意:当然,自己实现这些功能并不是那么困难。这将是相当简单的做法:
while(noComponentFound and notReachedTimeout){
look for component using FEST
sleep for a short delay
}
然而,最好不要被迫用这样的循环来打乱测试脚本。感觉在测试脚本中,等待组件并不是一项太不寻常的任务。因此,在我看来,应该有人支持在FEST中这样做。也许事实并非如此?是否不能等待组件?
有一种方法可以编写暂停和等待条件。以下是所需while(noComponentFound和notReachdTimeout)的示例。这可以通过Pause.Pause(new ComponentFoundCondition(…),timeout_milis)来完成。示例:
frame = WindowFinder.findFrame("frame0").using(robot);
//Wait for the event of loading tables in the GUI before we fail looking for them concurrently
final GenericTypeMatcher<JTable> matcher = new GenericTypeMatcher<JTable>(JTable.class) {
@Override protected boolean isMatching(JTable table){ return (table instanceof myTable && table.getColumnCount()<20); } //Condition has to be totally identitary for one particular component. If not, we will never reach condition and so a timeout will be thrown in next line
};
Pause.pause(new ComponentFoundCondition("Waiting for myTable to load before I look for it...", frame.robot.finder(), matcher, frame.target), 50000); //frame.target argument can be omitted. We also put an associated 50 sec timeout even if the condition is never satisfied
fixedTable = frame.table(matcher); //Look finally for the table now we are sure its loaded
你可以和不同的对手比赛。例如,如果框架下只有一种类型的表myTable,那么它将非常简单:
final ComponentMatcher matcher = new TypeMatcher(myTable.class); // We could use an easier TypeMatcher, because we would not need to add any additional distinction apart from the class type
Pause.pause(new Condition("Waiting for myTable to load...") { // If we are totally sure that there will be only one occurrence, we can use here the simplest form like above new ComponentFoundCondition("DebugMsg", frame.robot.finder(), matcher, frame.target)
@Override public boolean test() { return !frame.robot.finder().findAll(frame.target, matcher).size().isEmpty(); } // If not we need a custom condition that checks for >0 instead of =1 results like ComponentNotFound.
}, 50000);
问题还在于(component->frame).table(matcher)不接受TypeMatcher,而只接受GenericMatcher,所以我们无论如何都应该创建GenericMatcher
如果你找不到任何东西,总有一种方法可以选择静态地修复Pause.Pause(5,TimeUnit.SECONDS);
我不使用Fest,但Pause.Pause在这个页面上看起来很有趣:http://www.pushing-pixels.org/2009/09/23/using-fest-swing-to-test-flamingo-components.html