越写悦快乐之如何利用POM抽象基于Selenium构建的自动化页

2019-08-27  本文已影响0人  韬声依旧在路上
Page Objects - 图片来自简书App

我们上一篇文章使用Selenium的参数化注解构建多个测试套件,配合TestNG可以在命令行或者终端运行测试命令,今天的文章我们利用PageObjects来抽象你的页面对象,通过Page Objects、Page Sections、Page Element、PageFactory、PageFilters和Dependency Injection来抽象页面元素并结合Selenium自动化你的项目,接下来我为大家分享一下我的学习经验,希望对大家有所帮助。

开发环境

Maven Version

Maven版本 - 图片来自简书App

Build Version

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>me.weitao.app</groupId>
    <artifactId>selenium-pom-tour</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>selenium-pom-tour</name>
    <description>A Selenium POM Tour for Spring Boot</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <repositories>

        <repository>
            <id>AliYun Repository</id>
            <name>AliYun Repository</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.14.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.aventstack</groupId>
            <artifactId>extentreports</artifactId>
            <version>4.0.9</version>
        </dependency>
        <dependency>
            <groupId>com.aventstack</groupId>
            <artifactId>extentreports-testng-adapter</artifactId>
            <version>1.0.3</version>
        </dependency>
        <dependency>
            <groupId>uk.sponte.automation</groupId>
            <artifactId>selenium-pom</artifactId>
            <version>3.0.14</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <suiteXmlFiles>
                        <suiteXmlFile>${basedir}/src/test/resources/testng.xml</suiteXmlFile>
                    </suiteXmlFiles>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

什么是POM

POM是页面对象模型(Page Object Model)的简称,也是Selenium框架内置实现页面的抽象,我们可以利用它枚举、操作、查找页面的元素,通过驱动的方式来执行页面的行为。

原理解读

构建步骤

我们的示例项目以Spring Boot为基准项目来演示POM的使用

添加依赖

参考

构建基础Page对象

为了统一处理页面驱动和驱动等待等属性,我们声明了driverwait两个属性来存储,并声明构造方法和一些元素操作的方法,下面给出该文件的示例代码,仅供大家参考。

package me.weitao.app.pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;

/**
 * @author Watony Weng
 */

public class BasePage {

    public WebDriver driver;
    public WebDriverWait wait;

    public BasePage(WebDriver driver) {
        this.driver = driver;
        wait = new WebDriverWait(driver, 15);
    }

    public void waitVisibility(By elementBy) {
        wait.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(elementBy));
    }

    public void click(By elementBy) {
        waitVisibility(elementBy);
        driver.findElement(elementBy).click();
    }

    public void writeText(By elementBy, String text) {
        waitVisibility(elementBy);
        driver.findElement(elementBy).sendKeys(text);
    }

    public String readText(By elementBy) {
        waitVisibility(elementBy);
        return driver.findElement(elementBy).getText();
    }

    public void assertEquals(By elementBy, String expectedText) {
        waitVisibility(elementBy);
        Assert.assertEquals(readText(elementBy), expectedText);
    }

}

创建百度搜索实现类

假设我们想通过搜索关键字的方式打开百度首页,并输入搜索关键字Selenium PageObjects with Java,然后点击搜索结果页的链接并跳转到我们的博客园参考页面,最后通过Assert.assertEquals验证页面的标题,下面给出该文件的示例代码,仅供大家参考。

package me.weitao.app.pages;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;

/**
 * @author Watony Weng
 */

public class HomePage extends BasePage {

    private static final Logger LOG = LoggerFactory
            .getLogger(HomePage.class);

    private static final String BASE_URL = "http://www.baidu.com/";

    public HomePage(WebDriver driver) {
        super(driver);
    }

    /**
     * 页面搜索
     *
     * @param keyword 搜索关键字
     */
    public void testSearch(String keyword) {
        driver.get(BASE_URL);
        writeText(By.id("kw"), keyword);
        click(By.id("su"));
        LOG.info("after search url is :{}", driver.getCurrentUrl());
    }

    /**
     * 链接跳转
     */
    public void testClick() {
        driver.get(BASE_URL + "s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=Selenium%20PageObjects%20with%20Java&rsv_pq=90d822e0000248fe&rsv_t=14510I%2FJ6J5FZIjaYSQoQZ0hlAO4TG2Oa420IuApxqU%2FaK4dCRj4WZPCWUI&rqlang=cn&rsv_enter=0&rsv_dl=tb&rsv_sug3=30&inputT=347&rsv_sug4=347");
        click(By.xpath("//*[@id=\"4\"]/h3/a"));
        LOG.info("after click url is :{}", driver.getCurrentUrl());
    }

    /**
     * 标题验证
     */
    public void testTitle() {
        driver.get("https://www.cnblogs.com/NaCl/p/Selenium.html");
        Assert.assertEquals(readText(By.xpath("//*[@id=\"cb_post_title_url\"]")), "Selenium+PageObject+Java实现测试用例");
        LOG.info("after title url is :{}", driver.getCurrentUrl());
    }

}

创建测试基类

我们编写完页面对象后,接下来需要通过TestNG的注解来调用我们的Page对象的方法,比如搜索、点击、跳转等方法,下面给出该文件的示例代码,仅供大家参考。

package me.weitao.app.tests;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;

import java.util.concurrent.TimeUnit;

/**
 * @author Watony Weng
 */

public class BaseTest {

    public WebDriver driver;

    @BeforeClass
    public void setUp() {
        System.setProperty("webdriver.chrome.driver", "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chromedriver.exe");
        ChromeOptions chromeOptions = new ChromeOptions();
        chromeOptions.addArguments("--start-maximized");
        driver = new ChromeDriver(chromeOptions);
        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    }

    @AfterClass
    public void tearDown() {
        driver.quit();
    }

}

创建测试类

我们实现基类并获取driver属性,然后定义测试方法来测试Page对象,下面给出该文件的示例代码,仅供大家参考。

package me.weitao.app.tests;

import com.aventstack.extentreports.testng.listener.ExtentITestListenerClassAdapter;
import me.weitao.app.pages.HomePage;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;

/**
 * @author Watony Weng
 */

@Listeners({ExtentITestListenerClassAdapter.class})
public class HomeTest extends BaseTest {

    private HomePage homePage;

    @BeforeMethod
    public void before() {
        homePage = new HomePage(driver);
    }

    @Test(priority = 1)
    public void testHomeSearch() {
        homePage.testSearch("Selenium PageObjects with Java");
    }

    @Test(priority = 2)
    public void testHomeClick() {
        homePage.testClick();
    }

    @Test(priority = 3)
    public void testHomeTitle() {
        homePage.testTitle();
    }

    @AfterMethod
    public void after() {
        homePage = null;
    }

}

配置Test文件

完成以上的步骤后,我们可以在testng.xml文件中配置测试套件并配置可以启动的测试类,下面给出该文件的示例代码,仅供大家参考。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Selenium Automation Test Suite">

    <test name="PageObjects Test Case">
        <packages>
            <package name="me.weitao.app.tests">
                <exclude name="me.weitao.app.tests.BaseTest"/>
            </package>
        </packages>
    </test>

</suite>

配置测试报告选项

我们在pom文件中配置了extentreports,可以生成测试报告,配合maven-surefire-plugin查看可以生成不同的测试报告,这里给出extent.propertieshtml-config.xml配置文件的内容如下:

extent.reporter.avent.start=false
extent.reporter.bdd.start=false
extent.reporter.cards.start=false
extent.reporter.email.start=false
extent.reporter.html.start=true
extent.reporter.klov.start=false
extent.reporter.logger.start=false
extent.reporter.tabular.start=false
extent.reporter.avent.config=
extent.reporter.bdd.config=
extent.reporter.cards.config=
extent.reporter.email.config=
extent.reporter.html.config=src/test/resources/html-config.xml
extent.reporter.klov.config=
extent.reporter.logger.config=
extent.reporter.tabular.config=
extent.reporter.avent.out=target/extent-reports/AventReport/
extent.reporter.bdd.out=target/extent-reports/BddReport/
extent.reporter.cards.out=target/extent-reports/CardsReport/
extent.reporter.email.out=target/extent-reports/EmailReport/ExtentEmail.html
extent.reporter.html.out=target/extent-reports/HtmlReport/ExtentHtml.html
extent.reporter.logger.out=target/extent-reports/LoggerReport/
extent.reporter.tabular.out=target/extent-reports/TabularReport/
<?xml version="1.0" encoding="UTF-8"?>
<extentreports>
    <configuration>
        <!-- report theme -->
        <theme>standard</theme>

        <!-- document encoding -->
        <encoding>UTF-8</encoding>

        <!-- enable or disable timeline on dashboard -->
        <enableTimeline>true</enableTimeline>

        <!-- protocol for script and stylesheets -->
        <protocol>https</protocol>

        <!-- title of the document -->
        <documentTitle>Extent and TestNG Integration</documentTitle>

        <!-- report name - displayed at top-nav -->
        <reportName>Extent Report</reportName>

        <!-- create a report with all artifacts stored locally -->
        <enableOfflineMode>true</enableOfflineMode>

    </configuration>
</extentreports>

运行测试命令

我们最后在Idea的Terminal窗口执行以下命令,即可看到测试用例的运行结果。

npm clean test

查看测试报告

我们在target/extent-reports/HtmlReport目录下即可看到生成的测试报告。

参考

个人感想与收获

通过以上知识点的学习,我们知道了如何通过Page对象抽象我们的业务页面,然后借助Driver来控制浏览器,最后完成页面元素的一系列操作,我们自此完成了基本的自动化操作,再配合DataProvider更能把页面元素抽象化和实例化,让我们能更加从容地使用Selenium,借助这个工具完成能更方便地服务于我们的业务逻辑,接下来我们会继续探索Selenium这个框架,从其他方面优化、抽象、提升我们的测试水平,提升软件质量,服务更多的用户。希望大家保持学习的热情,继续充实自己的技能包,打造更高要求的研发团队,向更高更快的方向进发。

上一篇 下一篇

猜你喜欢

热点阅读