曾翻閱絕世武功目錄之一:http://java-source.net/。竟發現一個與我同名的測試工具-Jemmy。它是Java UI testing tool,原本是由NetBeans維護,最新版Jemmy3已移至Java.net網站了,位在https://jemmy.dev.java.net/。
在Bloghttp://zwshen.blogspot.com/2008/05/tutorial-of-jemmy.html對Jemmy的入門介紹還不錯。也整理如下:
1.在TestCase的setUp時,最重要的兩行:
private JFrameOperator mainWindow = null;
protected void setUp() throws Exception {
super.setUp();
new ClassReference("Calculator.CalculatorView").startApplication();
mainWindow = new JFrameOperator("Calculator");
}
Jemmy的設計理念是每一個GUI元件都對映到一個Operator的Class,上述程式碼的Calculator.CalculatorView是一個JFrame的Class,是故宣告一個JFrameOperator變數mainWindow。而new ClassReference("Calculator.CalculatorView").startApplication();則是啟動了這個GUI,接著mainWindow = new JFrameOperator("Calculator");則是用mainWindow承接了方才啟動的GUI的instance。
所以我一直納悶程式裡並沒有把new ClassReference的instance設給JFrameOperator的instance的動作,怎麼憑一個建構子傳"Calculator"字串就可以知道?在Jemmy的框架裡,被測系統和Jemmy需同在一個JVM上,Jemmy根據Reflection機制去JVM找,而"Calculator"其實是指這個GUI的title,若title沒有match就無法往下測,後續的Operator也都是Reflection機制處理的。
2.自動按鍵測試,在test method內容如下:
new JButtonOperator(mainWindow, new NameBasedChooser("sub")).push();
new JButtonOperator(mainWindow, "1").push();
new JButtonOperator(mainWindow, "2").push();
new JButtonOperator(mainWindow, "3").push();
在JButtonOperator傳的第一個參數是JFrameOperator的instance是沒問題,第二個參數等於是在第一個參數instance裡用Reflection找出Name屬性相同的JButton,然後push method就是按下去。比較令人玩味的是NameBasedChooser,原來第二個參數預設是找JButton的setText的值,而sub在計算機GUI是減號,是故要用NameBasedChooser,而NameBasedChooser要開發者實作Jemmy的介面:
import java.awt.Component;
import org.netbeans.jemmy.ComponentChooser;
class NameBasedChooser implements ComponentChooser {
private String name;
public NameBasedChooser(String componentName) {
name = componentName;
}
public boolean checkComponent(Component aComponent) {
String theName = aComponent.getName();
return (theName != null) && theName.equals(name);
}
public String getDescription() {
return "Matches Components named \"" + name + "\"";
}
}
這樣第二個參數變成會去Reflection getName屬性,而不是預設的getText。
Jemmy3已可支援到SWT、JavaFX,它原本是netbeans下的專案,應該很仇視IBM的SWT。現在變成由Java.net管理,這層束縛便解除了。