考慮如下屬性文件prop.properties,為上述代碼例子中的UI元素指定了 “別名”:
admin.username = loginForm:tbUsername
admin.loginbutton = loginForm:btnLogin
admin.events.createnewevent = adminHomeForm:_activitynew
admin.events.cancel = addEditEventForm:_IDcancel
admin.events.viewoldevents = adminHomeForm:_activityold
其中定位信息還是指向頁(yè)面的HTML對(duì)象,但我們?cè)跍y(cè)試腳本和UI元素之間引入一層抽象層。測(cè)試類(lèi)從屬性文件中讀取定位信息,從而實(shí)現(xiàn)UI映射。
頁(yè)面對(duì)象設(shè)計(jì)模式
頁(yè)面對(duì)象設(shè)計(jì)模式,可以提高自動(dòng)化測(cè)試腳本的維護(hù)性、減少代碼重復(fù),越發(fā)流行。頁(yè)面對(duì)象是一個(gè)面向?qū)ο蟮念?lèi),作為待測(cè)應(yīng)用對(duì)外提供的接口。測(cè)試代碼在需要和UI頁(yè)面交互時(shí),使用此頁(yè)面對(duì)象類(lèi)的方法。這樣做的好處是,如果UI頁(yè)面發(fā)生變化,測(cè)試代碼本身并不需要改變,只需要改變相應(yīng)的頁(yè)面對(duì)象的代碼。為適應(yīng)新UI頁(yè)面的所有更改,都位于一個(gè)地方。
頁(yè)面對(duì)象設(shè)計(jì)模式具有以下優(yōu)點(diǎn):
1、測(cè)試代碼和頁(yè)面相關(guān)的代碼,比如頁(yè)面元素定位信息(若使用UI映射,也包括定位信息的應(yīng)用),頁(yè)面布局等,完全分離;
2、可以維護(hù)單一的儲(chǔ)存庫(kù)來(lái)存儲(chǔ)頁(yè)面提供的服務(wù)或操作,而不是把他們分散在測(cè)試代碼中。
在這兩種情況下,這使得任何由于UI界面變化導(dǎo)致的修改,都可以在一個(gè)地方進(jìn)行修改。關(guān)于該技術(shù)的更多有用信息,可以在眾多的博客上找到。我們也鼓勵(lì)讀者去閱讀更多。 許多人寫(xiě)這樣的設(shè)計(jì)模式和超出本用戶(hù)指南的范圍,可以提供有用的提示。不過(guò),為了讓你開(kāi)始,我們將舉例說(shuō)明頁(yè)面對(duì)象的一個(gè)簡(jiǎn)單的例子。
首先,考慮一個(gè)例子,典型的自動(dòng)化測(cè)試,不使用頁(yè)面對(duì)象。
/***
* Tests login feature
*/
public class Login {
public void testLogin() {
selenium.type("inputBox", "testUser");
selenium.type("password", "my supersecret password");
selenium.click("sign-in");
selenium.waitForPageToLoad("PageWaitPeriod");
Assert.assertTrue(selenium.isElementPresent("compose button"),
"Login was unsuccessful");
}
}
這種方法有兩個(gè)問(wèn)題。
1、沒(méi)有分離測(cè)試代碼和待測(cè)應(yīng)用的定位器(在這個(gè)例子中是ID);兩者都交織在一個(gè)單一方法中。如果待測(cè)應(yīng)用UI改變了它的標(biāo)識(shí),布局,或登錄輸入和處理的方式變化,測(cè)試代碼本身必須改變。
2、ID定位信息分散在多個(gè)測(cè)試代碼中,所有的測(cè)試不得不使用此登錄頁(yè)面。
使用頁(yè)面對(duì)象技術(shù),上述測(cè)試代碼可以按如下方式重寫(xiě),為登錄頁(yè)面的頁(yè)面對(duì)象例子:
/**
* Page Object encapsulates the Sign-in page.
*/
public class SignInPage {
private Selenium selenium;
public SignInPage(Selenium selenium) {
this.selenium = selenium;
if(!selenium.getTitle().equals("Sign in page")) {
throw new IllegalStateException("This is not sign in page, current page is: "
+selenium.getLocation());
}
}
/**
* Login as valid user
*
* @param userName
* @param password
* @return HomePage object
*/
public HomePage loginValidUser(String userName, String password) {
selenium.type("usernamefield", userName);
selenium.type("passwordfield", password);
selenium.click("sign-in");
selenium.waitForPageToLoad("waitPeriod");
return new HomePage(selenium);
}
}