淺析selenium的page object模式


selenium目前比較流行的設計模式就是page object,那么到底什么是page object呢,簡單來說,就是把頁面作為對象,在使用中傳遞頁面對象,來使用頁面對象中相應的成員或者方法,能更好的提現java的面向對象和封裝特性,首先看一下官網的解釋:

Page Object Design Pattern

Page Object is a Design Pattern which has become popular in test automation for enhancing test maintenance and reducing code duplication. A page object is an object-oriented class that serves as an interface to a page of your AUT. The tests then use the methods of this page object class whenever they need to interact with the UI of that page. The benefit is that if the UI changes for the page, the tests themselves don’t need to change, only the code within the page object needs to change. Subsequently all changes to support that new UI are located in one place.

The Page Object Design Pattern provides the following advantages

1. There is a clean separation between test code and page specific code such as locators (or their use if you’re using a UI Map) and layout.

2. There is a single repository for the services or operations offered by the page rather than having these services scattered throughout the tests.

In both cases this allows any modifications required due to UI changes to all be made in one place. Useful information on this technique can be found on numerous blogs as this ‘test design pattern’ is becoming widely used. We encourage the reader who wishes to know more to search the internet for blogs on this subject. Many have written on this design pattern and can provide useful tips beyond the scope of this user guide. To get you started, though, we’ll illustrate page objects with a simple example.

First, consider an example, typical of test automation, that does not use a page object.

/***
 * 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"); } } 

There are two problems with this approach.

  1. There is no separation between the test method and the AUT’s locators (IDs in this example); both are intertwined in a single method. If the AUT’s UI changes its identifiers, layout, or how a login is input and processed, the test itself must change.
  2. The ID-locators would be spread in multiple tests, in all tests that had to use this login page.

Applying the page object techniques, this example could be rewritten like this in the following example of a page object for a Sign-in page.

/**
 * 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); } } 

and page object for a Home page could look like this.

/**
 * Page Object encapsulates the Home Page  */ public class HomePage { private Selenium selenium; public HomePage(Selenium selenium) { if (!selenium.getTitle().equals("Home Page of logged in user")) { throw new IllegalStateException("This is not Home Page of logged in user, current page" + "is: " +selenium.getLocation()); } } public HomePage manageProfile() { // Page encapsulation to manage profile functionality return new HomePage(selenium); } /*More methods offering the services represented by Home Page  of Logged User. These methods in turn might return more Page Objects  for example click on Compose mail button could return ComposeMail class object*/ } 

So now, the login test would use these two page objects as follows.

/***
 * Tests login feature  */ public class TestLogin { public void testLogin() { SignInPage signInPage = new SignInPage(selenium); HomePage homePage = signInPage.loginValidUser("userName", "password"); Assert.assertTrue(selenium.isElementPresent("compose button"), "Login was unsuccessful"); } }

官網中使用的代碼例子是selenium1的方式,為了方便我使用webdirver做了實現,並使用知乎登錄作為例子。

思路:

A:打開瀏覽器

B:訪問www.zhihu.com

C:登錄

D:登錄后,主頁驗證是否登錄成功

以上四個步驟用到了2個頁面,登錄頁面和主頁,下面我們就對這兩個頁面進行封裝。

1.新建一個HomePage類。

package com.pageobject1;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.testng.Assert;

/** 
 * @author QiaoJiafei 
 * @version 創建時間:2016年2月26日 上午10:01:51 
 * 類說明 
 */
public class HomePage {
    private WebDriver driver;
    WebElement element_account;
    
    public HomePage(WebDriver driver) {
        if(!driver.getTitle().equals("首頁 - 知乎")) {
            throw new IllegalStateException("This is not Home Page of logged in user, current page" +
                    "is: " +driver.getTitle());
        }
        element_account = driver.findElement(By.id(":0"));
    }
    
    public HomePage manageProfile() {
        // Page encapsulation to manage profile functionality
        String text = element_account.getText();
        Assert.assertEquals(text, "喬葉葉");
        return new HomePage(driver);
}
  public XXXpage clickhrep() {
  //點擊某個鏈接的方法,並返回跳轉后的頁面對象
  
  return XXXpage(driver);
} }

2.新建一個LoginPage類

package com.pageobject1;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;

import com.google.common.base.Predicate;

/** 
 * @author QiaoJiafei 
 * @version 創建時間:2016年2月26日 上午9:55:23 
 * 類說明 
 */
public class LoginPage {
    
    private WebDriver driver;
    WebElement element_username;
    WebElement element_password;
    WebElement element_submit;
    
    
    public LoginPage(WebDriver driver) {
        // TODO Auto-generated constructor stub
        this.driver = driver;
        if(!driver.getTitle().equals("知乎 - 與世界分享你的知識、經驗和見解")) {
            throw new IllegalStateException("This is not sign in page, current page is: "
                    +driver.getTitle());
        }
        element_username = driver.findElement(By.name("account"));
        element_password = driver.findElement(By.name("password"));
        element_submit =  driver.findElement(By.xpath("/html/body/div[1]/div/div[2]/div[2]/form/div[3]/button"));
    }
    public HomePage loginValidUser(String userName, String password) {
        element_username.sendKeys(userName);
        element_password.sendKeys(password);
        element_submit.click();
        WebDriverWait wait = new WebDriverWait(driver, 10);
        wait.until(new ExpectedCondition<WebElement>(){

            @Override
            public WebElement apply(WebDriver arg0) {
                // TODO Auto-generated method stub
                return arg0.findElement(By.id(":0"));
            }
            
        }).isDisplayed();
     //注意根據實際業務,返回相應頁面對象
return new HomePage(driver); } }

3.新建一個測試類

package com.pageobject1;

import java.sql.Driver;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;



/** 
 * @author QiaoJiafei 
 * @version 創建時間:2016年2月26日 上午10:20:29 
 * 類說明 
 */
public class TestLogin {
    WebDriver driver = null;
    @BeforeClass
    public void beforeClass() {
        String key = "webdriver.firefox.bin";
        String value = "C:/Program Files (x86)/Mozilla Firefox/firefox.exe";
        System.setProperty(key, value);
        driver = new FirefoxDriver();
        
        driver.manage().window().maximize();
        driver.get("https://www.zhihu.com/#signin");
    }
    
    @AfterClass
    public void afterClass() {
        driver.quit();
    }
    
    @Test
    public void testLogin() {
        
        LoginPage loginPage = new LoginPage(driver);
        HomePage homePage = loginPage.loginValidUser("XXXXX@163.com", "XXXXX");
        /*
         * 下面就可以使用homepage對象來做操作,如:
         * homePage.manageProfile();
         * 
         * */
        Assert.assertEquals(driver.getTitle(), "首頁 - 知乎");
    }
}

由此可見,在測試類中,操作的基本都是頁面對象,邏輯清晰,代碼簡單,在后期的維護中,如果那個頁面的元素發生變化,則只需要更改相應頁的頁面類即可,不需要更改測試類的邏輯。

看到這里有的也許會問:每次都要求返回一個頁面對象,有時不確定怎么辦?

我的解決辦法是:在實際的自動化測試中,是先有測試用例,后編寫測試腳本,所以基本每個頁面傳遞對象都可以確定,如在主頁我點擊一篇文章會跳轉一個文章頁面,點擊個人頭像灰跳轉一個個人頁面,在就是在主頁類中寫兩個方法,一個方法返回文章頁面,一個方法返回個人頁面,依次類推……

好了,這篇文件就先簡單介紹一下page object的設計思想及用法,以后會寫一篇文章,如何在框架中使用這種模式

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM