美文网首页appium
自动化设计模式 POM (Page Object Model)

自动化设计模式 POM (Page Object Model)

作者: 爱sa笑的菇凉 | 来源:发表于2020-06-11 11:39 被阅读0次

    本文将使用Maven + TestNG + Java + Selenium 的项目来作为例子来讲解如何实现POM。

    1.POM是什么

    Page Object Model 是一种自动化测试的设计模式,为Web UI元素创建Object Repository。它的优点就是减少了代码的重复,提高了测试维护。

    一般情况下,POM的项目需要包括3部分:

    • PageModle:每个页面都应该有自己的的PageClass文件,这个PageClass将标识该页面的Web元素,并包含对这些Web元素执行操作的方法
    • TestCase:测试用例管理部分,一个功能点可以对应一个或者多个case,尽可能的提高覆盖率
    • Utilities:可以包含一些报告等内容
    按照上边的解释,我们可以把项目分为三部分,在项目中创建三个packages: pages,tests,utilities,如下图所示:

    2.使用POM的好处

    1. POM模式使得测试用例和页面元素操作分开,这样可以使我们的代码更干净,更容易理解,且更容易维护;
    2. 对象存储库独立于测试用例,因此我们可以使用不同的工具为不同的目的使用相同的对象存储库。 例如,我们可以将POM与用于功能测试的Test NG/JUnit集成,同时与用于验收测试的JBehave/Cucumber集成;
    3. 测试用例更加简短,而且可重用页面元素和方法,代码变得更少,更简洁;
    4. 方法使用更真实的名称,这些名称可以很容易地与UI中发生的操作映射。例如:如果单击按钮后,回返回主页面,方法名称将类似于gotoHomePage(),易于理解。

    3.如何创建一个POM项目

    接下来我们通过一个简单的测试用例(登录账户的验证)来进行扩展,一步一步演变成POM的模式的项目。

    最原始的代码如下:

        @Test
        public void ValidPasswordLogin(){
    
            //1. Open browser and open test url
            System.setProperty("webdriver.chrome.driver", "Driver/chromedriver");
            WebDriver driver;
            driver = new ChromeDriver();
            driver.manage().window().maximize();
            driver.get("http://jinshuju.com");
    
            //2. Test part
    
                //2. 1 Home page: Click login button go to login page
            driver.findElement(By.cssSelector(".login-link")).click();
    
                //2. 2 Login page: Input username and password to login
            driver.findElement(By.id("auth_key")).sendKeys("131****8959");
            driver.findElement(By.cssSelector(".gd-btn.gd-btn-primary-solid")).click();
            driver.findElement(By.id("password")).sendKeys("Abcdef");
            driver.findElement(By.cssSelector(".gd-btn.gd-btn-primary-solid")).click();
            Assert.assertEquals(driver.findElement(By.className("validate-invalid")).getText(),"密码错误,请输入正确的密码(还剩余4次)");
    
            //3. Quite browser
            driver.quit();
        }
    
    1. 首先,通过上述代码,可以看到一些common的方法例如:sendKeys, click, getText, assert,几乎在每个页面,都会频繁使用这些方法。如果单纯的使用Selenium自己的这些方法,可能会遇到一些问题,例如因为加载慢某个按钮还没有加载完成,但是已经触发了点击事件,此时会因为找不到按钮而失败,等等很多类似的问题。基于这些问题,我们首先可以对selenium这些最基本的方法进行重写。在pages package下边创建一个BasePage.java文件来重写这些方法,之后所有的页面都继承于BasePage类。

    BasePage.java

    package pages;
    import org.junit.Assert;
    import org.openqa.selenium.By;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.support.ui.ExpectedConditions;
    import org.openqa.selenium.support.ui.WebDriverWait;
    
    public class BasePage {
    
        public WebDriver driver;
        public WebDriverWait wait;
    
        //Constructor
        public BasePage (WebDriver driver){
            this.driver = driver;
            wait = new WebDriverWait(driver,20);
        }
    
        //Wait
        public void waitVisibility(By elementBy) {
            wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(elementBy));
        }
    
        //Click
        public void click(By elementBy){
            waitVisibility(elementBy);
            driver.findElement(elementBy).click();
        }
    
        //Write Text
        public void writeText (By elementBy, String text) {
            waitVisibility(elementBy);
            driver.findElement(elementBy).sendKeys(text);
        }
    
        //Read Text
        public String readText (By elementBy) {
            waitVisibility(elementBy);
            return driver.findElement(elementBy).getText();
        }
    
        //Assert
        public void assertEquals (By elementBy, String expectedText) {
            waitVisibility(elementBy);
            Assert.assertEquals(readText(elementBy), expectedText);
        }
    }
    
    1. 接下来,分析整个代码块,可以分为三部分:
    1. 在执行测试步骤之前,我们需要先打开浏览器,输入测试的地址;
    2. 执行测试用例;
    3. 执行完测试用例之后,关闭浏览器。
    • 第1和3这两部分:
      分析: 因为每条测试用例都会打开浏览器和关闭浏览器,所以我们可以将他们放在一个BaseTest类中,使用@BeforeMethod和@AfterMethod注解(这个是TestNG的注解,如果不知道请学习TestNG的注解),在每一个测试方法执行之前都会先执行@BeforeMethod,在每一个测试方法执行之后都会执行@AfterMethod。
      做法: 在tests的Package下边创建一个BaseTest.java类,将1和3 两部分写在这个BaseTest类中:

    BaseTest.java

    package tests;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.testng.annotations.*;
    
    public class BaseTest {
        public WebDriver driver;
    
        @BeforeMethod
        public void setUp() {
            //1. Open browser and open test url
            System.setProperty("webdriver.chrome.driver", "Driver/chromedriver");
            driver = new ChromeDriver();
            driver.manage().window().maximize();
            driver.get("http://jinshuju.com");
        }
    
        @AfterMethod
        public void quiteBrowser() {
            //3. Quite browser
            driver.quit();
        }
    }
    
    • 第2部分
      分析: 第2部分是测试代码部分,可以看到 1). 要对两个页面(Home page 和Login page)进行操作;2). 每个页面都有各自的元素和方法。所以我们可以按照页面进行拆分,每个页面为一个类,每个页面的类中包含对应页面的元素部分和方法部分,这样就比较清晰,而且当添加新的Case的时候也可以去复用现有的方法。
      做法: 在pages这个package下边创建一个HomePage.java 类和一个LoginPage.java 类,将各自页面的方法也在各自页面中。 然后在每个page类中分为定位元素和方法两部分:

    HomePage.java

    package pages;
    import org.openqa.selenium.By;
    import org.openqa.selenium.WebDriver;
    
    public class HomePage extends BasePage{
    
        //Constructor
        public HomePage(WebDriver driver) {
            super(driver);
        }
    
        //Elements
        By loginButton = By.cssSelector(".btn-outline");
    
        //Actions
        public void clickLogin(){
            click(loginButton);
        }
    }
    

    LoginPage.java

    package pages;
    import org.openqa.selenium.By;
    import org.openqa.selenium.WebDriver;
    import org.testng.Assert;
    
    public class LoginPage extends BasePage{
    
        //Constructor
        public LoginPage(WebDriver driver) {
            super(driver);
        }
    
        //Elements
        By userNameInput = By.id("auth_key");
        By loginButton = By.cssSelector(".btn-lg");
        By passwordInput = By.id("password");
        By errorMessage = By.cssSelector(".alert");
    
        //Actions
        public void inputUsernamePwd(String userName, String password){
            writeText(userNameInput,userName);
            writeText(passwordInput,password);
            click(loginButton);
        }
    
        public void verifyErrorMessage(String expectedErrorMessage){
            Assert.assertEquals(readText(errorMessage),expectedErrorMessage);
        }
    }
    
    1. 此时,已经给每个页面创建了自己的类,而且每个页面类包含自己的元素定位和方法。接下来,需要创建测试用例来调用每个页面的方法,在tests package 下创建 loginTests.java 类,内容如下。注释部分是之前的代码,已经被新的代码代替。这样测试用例部分就很清晰,很简洁。
      loginTests.java
    package tests;
    import org.openqa.selenium.WebDriver;
    import org.testng.annotations.Test;
    import pages.HomePage;
    import pages.LoginPage;
    
    public class loginTests extends BaseTest{
    
        public static WebDriver driver;
        public static LoginPage loginPage = new LoginPage(driver);
        public static HomePage homePage = new HomePage(driver);
    
        @Test
        public void InvalidPasswordLogin(){
            
            //driver.findElement(By.cssSelector(".btn-outline")).click();
            homePage.clickLogin();
            
            //driver.findElement(By.id("auth_key")).sendKeys("131****8959");
            //driver.findElement(By.id("password")).sendKeys("Abcdef");
            //driver.findElement(By.cssSelector(".btn-lg")).click();
            loginPage.inputUsernamePwd("131****8959","Abcdef");
            
            //Assert.assertEquals(driver.findElement(By.cssSelector(".alert")).getText(),"账号密码不正确");
            loginPage.verifyErrorMessage("账号密码不正确");
        }
    }
    
    1. 分析结束后,我们的代码结构如下图:

    相关文章

      网友评论

        本文标题:自动化设计模式 POM (Page Object Model)

        本文链接:https://www.haomeiwen.com/subject/uhfetktx.html