如 果頁面中包括JavaScript,使用HtmlUnit測試,基本上不用什麼改變,因為HtmlUnit就像個無畫面的瀏覽器,有JavaScript 的話也會自動執行,如果JavaScript會改變畫面,雖然沒有畫面,但畫面實質就是依DOM樹結構,所以要判斷畫面有無改變,就是判斷DOM樹結構或 各節點有無變化。
舉例來說,如果想測試 修改文件 中第二個範例,可以如下:
WebClient webClient = new WebClient(BrowserVersion.FIREFOX_3);
HtmlPage page = webClient.getPage(
"https://openhome.cc/Gossip/JavaScript/samples/ModifyNodes-2.html");
page.getElementById("image").click();
assertEquals(
page.getElementById("container2"),
page.getElementById("image").getParentNode());
page.getElementById("image").click();
assertEquals(
page.getElementById("container1"),
page.getElementById("image").getParentNode());
HtmlPage page = webClient.getPage(
"https://openhome.cc/Gossip/JavaScript/samples/ModifyNodes-2.html");
page.getElementById("image").click();
assertEquals(
page.getElementById("container2"),
page.getElementById("image").getParentNode());
page.getElementById("image").click();
assertEquals(
page.getElementById("container1"),
page.getElementById("image").getParentNode());
打算測試Ajax也是可行的,例如想測試 建立非同步物件 中的範例,可以如下:
WebClient webClient = new WebClient();
HtmlPage page = webClient.getPage(
"https://openhome.cc/Gossip/JavaScript/samples/XMLHttpRequest-1.html");
page.getElementById("req").click();
assertEquals(1, page.getElementsByTagName("table").size());
HtmlPage page = webClient.getPage(
"https://openhome.cc/Gossip/JavaScript/samples/XMLHttpRequest-1.html");
page.getElementById("req").click();
assertEquals(1, page.getElementsByTagName("table").size());
(在撰寫文件時的HtmlUnit 2.8中,指定WebClient的版本為Firefox時Ajax請求就會失敗!)
實際上,HtmlUnit預設會以同步處理方式來發出請求與接收回應,這是由WebClient預設的AjaxController來控制,所以上例的click()後,會等到伺服端有回應後才會執行下一行。WebClient會在真正發出Ajax請求前,呼叫AjaxController的processSynchron()方法,這個方法的傳回值決定了最後要以同步(true)或非同步(false)發出請求,如果你想要在Ajax請求發出前作一些動作,或決定是否同步請求,則可以如下:
webClient.setAjaxController(new AjaxController() {
@Override
public boolean processSynchron(HtmlPage page, WebRequest request,
boolean async) { // async 預設是傳入false
// 作一些前置處理
return false; // false 表示非同步處理
}
});
預設的AjaxController其實只作了以下:
public class AjaxController implements Serializable {
...
public boolean processSynchron(final HtmlPage page,
final WebRequest request, final boolean async) {
return !async;
}
}
...
public boolean processSynchron(final HtmlPage page,
final WebRequest request, final boolean async) {
return !async;
}
}
AjaxController直接與主執行緒同步,如果想與運行測試時的執行緒同步,而非主執行緒,則可以設定NicelyResynchronizingAjaxController。例如:
webClient.setAjaxController(new NicelyResynchronizingAjaxController());
如果頁面中的JavaScript有alert()函式,則可以註冊AlertHandler,例如使用CollectingAlertHandler實作:
CollectingAlertHandler alertHandler = new CollectingAlertHandler();
webClient.setAlertHandler(alertHandler);
webClient.setAlertHandler(alertHandler);
在JavaScript執行時若執行了alert(),則會被CollectionAlertHandler收集,你可以使用getCollectedAlerts()以List<String>取得alert()的訊息。類似地,像confirm()、prompt()等,都有對應的setConfirmHandler()、setPromptHandler()可以使用。
有關ActiveX的模擬,可以參考官方網站上 Use ActiveX 的說明。