一、在实现自动化过程中,会有很多重复的代码,我们在维护代码时会很困难,如果想解决这个问题,我们就需要使用PageObjectModel(页面对象模型)的方式来进行自动化代码的书写。

二、案例演示

以该网站的机票预订操作为例:https://www.expedia.com/?siteid=100001&langid=2052&currency=CNY

1、首先我们在eclipse中创建2个包,pageclasses和pomtestcase,然后在pageclasses中创建一个用于存放单个元素的类SearchPage,在pomtestcase中创建一个类用于调用创建好的元素,这样就能够把页面元素和测试的用例代码分开存放,便于维护和调用。

2、在SearchPage类中将查找元素直接封装到方法中

package pageclasses;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement; public class SearchPage { // 首先声明一个WebElement类型的变量
public static WebElement element = null ; // 加元素封装到方法中 /**
* 返回"机票按钮"元素
* @param driver
* @return
*/
public static WebElement ticketButton(WebDriver driver) {
element = driver.findElement(By.id("tab-flight-tab-hp"));
return element;
} /**
* 返回"出发文本框"元素
* @param driver
* @return
*/
public static WebElement startText(WebDriver driver) {
element = driver.findElement(By.xpath("//input[@id='flight-origin-hp-flight']"));
return element;
} /**
* 返回"飞往文本框"元素
* @param driver
* @return
*/
public static WebElement endText(WebDriver driver) {
element = driver.findElement(By.xpath("//input[@id='flight-destination-hp-flight']"));
return element;
} /**
* 返回"出发日期框"元素
* @param driver
* @return
*/
public static WebElement startData(WebDriver driver) {
element = driver.findElement(By.xpath("//input[@id='flight-departing-hp-flight']"));
return element;
} /**
* 返回"返回日期框"元素
* @param driver
* @return
*/
public static WebElement returnData(WebDriver driver) {
element = driver.findElement(By.xpath("//input[@id='flight-returning-hp-flight']"));
return element;
} /**
* 返回"点击登录"元素
* @param driver
* @return
*/
public static WebElement searchButton(WebDriver driver) {
element = driver.findElement(By.xpath("//div[@class='cols-nested ab25184-submit']//button[@class='btn-primary btn-action gcw-submit']"));
return element;
}
}

元素封装好以后,在测试类中可以直接被多出重复调用,但前端代码路径发生变化,那么就只需要修改该类中相对应的元素路径即可,测试类中调用到该元素的路径也一并进行了修改,提高了我们对自动化代码维护时的工作效率。

3、在PageObjectModel类中直接调用,这样就简化了测试类中的代码量

 package pomtestcase;

 import static org.junit.jupiter.api.Assertions.*;

 import java.util.concurrent.TimeUnit;

 import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver; import pageclasses.SearchPage; class PageObjectModel { WebDriver driver;
String url; @BeforeEach
void setUp() throws Exception {
driver = new ChromeDriver();
url = "https://www.expedia.com/?siteid=100001&langid=2052&currency=CNY";
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get(url);
} @Test
void test() throws InterruptedException {
// 调用封装了元素的SearchPage类中的“机票”按钮元素
SearchPage.ticketButton(driver).click();
Thread.sleep(1000);
// 调用封装了元素的SearchPage类中的“出发”输入框元素
SearchPage.startText(driver).sendKeys("长沙, 中国 (CSX-黄花国际机场)");
Thread.sleep(1000);
// 调用封装了元素的SearchPage类中的“返回”输入框元素
SearchPage.endText(driver).sendKeys("上海, 中国 (PVG-浦东国际机场)");
// 调用封装了元素的SearchPage类中的“出发”日期输入框元素
SearchPage.startData(driver).sendKeys("2019/07/06");
// 调用封装了元素的SearchPage类中的“返回”日期输入框元素
SearchPage.returnData(driver).sendKeys("2019/07/07");
// 调用封装了元素的SearchPage类中的“搜索”按钮元素
SearchPage.searchButton(driver).click();
} @AfterEach
void tearDown() throws Exception {
Thread.sleep(2000);
driver.quit();
}
}

三、在“案例演示”中我们只封装了查找元素的方法,但为了调用方便,我们可以将输入动作或者点击动作一并进行封装,进一步简化测试类中的代码量

将“出发地”文本框元素输入进行封装:

封装后调用:

如果有不明白的小伙伴可以加群“555191854”问我,群里都是软件行业的小伙伴相互一起学习。

内容具有连惯性,未标注的地方可以看前面的博客,这是一整套关于ava+selenium自动化的内容,从java基础开始。

欢迎关注,转载请注明来源。

章节十五、2-PageObjectModel的更多相关文章

  1. 章节十五、5-记录日志---Log4j

    一.为什么要用Log4j记录日志? 日志记录对于任何应用程序都非常重要. 它可以帮助我们快速调试代码,通过收集代码执行的信息让代码容易维护. 二.Log4j 是什么? Apache为Java提供的日志 ...

  2. 章节十五、3-对象仓库、Page Factory实例应用

    一.如何创建对象仓库 package pageclasses; import org.openqa.selenium.WebDriver; import org.openqa.selenium.Web ...

  3. 章节十五、6-log4 2-用默认的配置

    一.实例演示 package log4jtutorial; import org.apache.logging.log4j.LogManager; import org.apache.logging. ...

  4. 章节十五、7- 配置文件-Console Logging

    一.创建xml文件 1.创建xml文件 在项目中我们需要专门建一个文件夹来放xml文件或者是其它文件. 2.然后对文件夹进行命名 3.选择new  其它 4.选择XML File 5.给xml文件命名 ...

  5. 章节十五、8-配置文件File Logging

    一.如何将log输出到文件中? 1.配置xml文件 <?xml version="1.0" encoding="UTF-8"?> <Confi ...

  6. 章节十五、9-自定义Loggers

    一.如何给不同的包设置不同的日志级别? 1.针对不同的包来记录不同级别的日志信息 2.在日志xml配置文件中加入配置信息(红色标注) <?xml version="1.0" ...

  7. NeHe OpenGL教程 第三十五课:播放AVI

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  8. WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇]

    原文:WCF技术剖析之二十五: 元数据(Metadata)架构体系全景展现[元数据描述篇] 在[WS标准篇]中我花了很大的篇幅介绍了WS-MEX以及与它相关的WS规范:WS-Policy.WS-Tra ...

  9. thinkphp URL规则、URL伪静态、URL路由、URL重写、URL生成(十五)

    原文:thinkphp URL规则.URL伪静态.URL路由.URL重写.URL生成(十五) 本章节:详细介绍thinkphp URL规则.URL伪静态.URL路由.URL重写.URL生成 一.URL ...

随机推荐

  1. MySQL事务和锁——《MySQL DBA工作笔记》

    MySQL事务 事务存在的原因 事务存在的目的:保证用户对数据操作对数据是安全的.(比如说银行卡余额) 事务的特性--ACID 原子性:一个事务要么全部执行,要么不执行 一致性:事务开始和结束时,数据 ...

  2. docker安装执行问题

    ubuntu14.04上安装docker问题: sudo apt-get update curl -fsSL https://get.docker.com -o get-docker.sh sh ge ...

  3. C++ int 和string互相转化

    1.int转换成string );//"-12" );//"12" +);//"1" 2.string转换成int );//"-1 ...

  4. cicros安装

    1.下载与安装依赖包 wget https://github.com/libgd/libgd/releases/download/gd-2.2.5/libgd-2.2.5.tar.gz tar zxv ...

  5. 【转】python中的闭包

    转自:http://www.cnblogs.com/ma6174/archive/2013/04/15/3022548.html python中的闭包 什么是闭包? 简单说,闭包就是根据不同的配置信息 ...

  6. spring cloud 与spring boot 版本不匹配引发的问题总结

    为了将前期项目慢慢转移到微服务上,今天开始搭建eureka服务时,出现以下错误: org.springframework.context.ApplicationContextException: Un ...

  7. netstat查看端口状态

    netstat netstat -tunlp 用于显示 tcp,udp 的端口和进程等相关情况. netstat 查看端口占用语法格式: netstat -tunlp | grep 端口号 -t (t ...

  8. torch_13_自定义数据集实战

    1.将图片的路径和标签写入csv文件并实现读取 # 创建一个文件,包含image,存放方式:label pokemeon\\mew\\0001.jpg,0 def load_csv(self,file ...

  9. @Resource和@Autowire用谁?

    我选了@Resource 1.当注入的属性是接口 1.1在接口只有一个实现类的时候,@Resource和@Autowire 在功能上是没有区别的 1.2如果接口有多个实现类,在写法上,@Autowir ...

  10. tf.clip_by_value

    tf.clip_by_value(t, clip_value_min, clip_value_max, name=None) 功能:基于定义的min与max对tesor数据进行截断操作,目的是为了应对 ...