10 Page Object 模型
10.1 概述
? ? 在針對一個WEB頁面撰寫自動化測驗用例時,需要參考頁面中的元素(資料)才能進行操作(動作)并顯示出頁面內容,如果撰寫的測驗用例是直接針對WEB頁面元素進行操作,則無法應對經常發生變化的WEB頁面,增加日后自動化代碼的維護成本,而Page Object模型就是針對WEB頁面和元素細節的封裝,并對外提供應用級別的API,從而擺脫對WEB頁面的高耦合情況,示意圖如下所示:

? ? 針對以上示例,可以大概總結出大概做法,如下所示:
- 以頁面為單位,獨立建立模型
- 隱藏實作細節
- 本質是面向介面編程
以上示例圖片位置:https://martinfowler.com/bliki/PageObject.html
10.2 定義
? ? Page Object模型(簡稱為PO模式)是一種設計模式,其核心是分層,實作松耦合,從而實作代碼復用和其易維護性,利用PO模型,為每個網頁建立兩個類:
- Page類
? ? 將每個頁面封裝為Page類,頁面元素為Page類成員變數,頁面功能為Page類方法里面
- Test類
? ? 針對Page類定義的測驗類,在測驗類中呼叫Page類中方法完成測驗,其使用Page類中的方法與頁面UI元素進行互動操作,若UI發生變化,僅需要更新Page類,測驗類無需要更改,
10.3 為什么使用Page Object模式
? ? WEB由各種WEB元素(文本框、復選框、多選/單選按鈕等)組成,測驗代碼與這些元素進行互動,如果不能正確管理定位器,則代碼的復雜性將成倍增加,當測驗代碼和定位器的重復使用,將降低代碼的可讀性,從而進一步加大測驗代碼的維護成本, 隨著專案和需求的不斷變化,開發和測驗代碼的復雜性會不斷增加,維護性也隨之增加,因此,需要一種方法來解決這種問題,所以我們需要使用PO來嘗試解決這一類問題,
10.4 Page Object模型優點
? ? 主要優點如下所示:
- 提高代碼可復用性
? ? 不同PO類中的Pabe Object方法可以在不同的測驗用例中復用,極大提高代碼的復用性,
- 提高代碼可維護性
? ? 因測驗場景和定位器是代碼分開,使代碼更加清晰,極大提高代碼的可維護性,
- 減少UI對用例造成的影響
? ? 盡管UI經常發生變更,也僅需要修改少量代碼來應對更改,從而減少其帶來的影響,
10.5 Page Object示例
10.5.1 演示環境搭建
? ? 我們以官方提供的示例為演示,操作步驟如下所示:
- 1、訪問官方網址,其網址:https://docs.cypress.io/examples/examples/recipes#Testing-the-DOM
- 2、點擊HTML Web Forms跳轉到Github創建,下載原始碼
- 3、將代碼放置到指定目錄并在當前目錄打開終端,執行以下命令,以啟動服務
npm install minimist morgan body-parser express-session express hbs --save-dev
npm start server.js
- 4、在瀏覽器中訪問

? ? 默認正確的用戶名和密碼,在server.js中,可以自行修改,如下所示:

10.5.2 演示代碼
? ? 本代碼僅僅是演示在Cypress中的Page Object模式(注意與Selenium的區別),主要示例代碼如下所示:
- 1、新建定位器檔案loginPageLoctor.json,用于存盤元素定位器
{
"loginPage":{
"username":"input[name=\"username\"]",
"passwd":"input[name=\"password\"]",
"submit":"button[type=\"submit\"]",
"loginFailedPrompt":".error"
}
}
- 2、新建Page類loginPage.js,用于封裝物件和定位元素
/// <reference types="cypress" />
import LoginPageLocator from "./loginPageLoctor.json"
export default class LoginPage{
constructor(visitUrl){
this.url=visitUrl;
}
get username(){
return cy.get(LoginPageLocator.loginPage.username);
}
get passwd(){
return cy.get(LoginPageLocator.loginPage.passwd);
}
get submit(){
return cy.get(LoginPageLocator.loginPage.submit);
}
get errorPrompt(){
return cy.get(LoginPageLocator.loginPage.loginFailedPrompt);
}
get successUrl(){
return cy.url();
}
visit(){
cy.visit(this.url);
}
login(name,pwd) {
if ( name !="" && pwd !=""){
this.username.type(name);
}
if(pwd!=""){
this.passwd.type(pwd);
}
this.submit.click();
}
}
- 3、新建資料檔案loginData.json,用于存盤登錄的資料和資料驅動
{
"success": [
{
"caseTitle": "正確的用戶名和密碼,登錄成功",
"user": "jane.lane",
"pwd": "password123",
"checkpoint": "/dashboard"
}
],
"failed": [
{
"caseTitle": "錯誤的用戶名和正確的密碼,登錄失敗",
"user": "Surpass",
"pwd": "password123",
"checkpoint": "Username and/or password is incorrect"
},
{
"caseTitle": "正確的用戶名和錯誤的密碼,登錄失敗",
"user": "jane.lane",
"pwd": "Surpass",
"checkpoint": "Username and/or password is incorrect"
},
{
"caseTitle": "錯誤的用戶名和錯誤的密碼,登錄失敗",
"user": "Surpass",
"pwd": "Surpass",
"checkpoint": "Username and/or password is incorrect"
}
]
}
- 4、新建測驗類testLogin.spec.js,測驗用例代碼
/// <reference types="cypress" />
import LoginPage from "./loginPage"
import UserData from "./loginData.json"
describe('登錄測驗', () => {
let baseUrl = "http://localhost:7077/login";
let login = new LoginPage(baseUrl);
beforeEach(() => {
login.visit(baseUrl);
});
UserData.success.forEach((item)=>{
it(item.caseTitle, () => {
login.login(item.user,item.pwd);
login.successUrl.should("contain",item.checkpoint)
});
});
UserData.failed.forEach((item)=>{
it(item.caseTitle, () => {
login.login(item.user,item.pwd);
login.errorPrompt.should("contain",item.checkpoint)
});
});
});
? ? 最終的運行結果如下所示:

原文地址:https://www.jianshu.com/p/f6749544d6f8
本文同步在微信訂閱號上發布,如各位小伙伴們喜歡我的文章,也可以關注我的微信訂閱號:woaitest,或掃描下面的二維碼添加關注:

作者: Surpassme
來源: http://www.jianshu.com/u/28161b7c9995/
http://www.cnblogs.com/surpassme/
宣告:本文著作權歸作者所有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出 原文鏈接 ,否則保留追究法律責任的權利,如有問題,可發送郵件 聯系,讓我們尊重原創者著作權,共同營造良好的IT朋友圈,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/509521.html
標籤:其他
下一篇:校招總結
