先来看一个在腾讯课堂首页搜索机构的操作步骤:

1:首先打开腾讯课堂的首页:https://ke.qq.com

2:点击课程或机构的下拉选择图标

3:选择机构

4:在搜索框输入要搜索的机构名称

5:点击查找图标查找机构,跳转到查找结果页面

6:检查查找出的机构名称

7:点击机构logo跳转详情页面

上述操作涉及到两个页面,腾讯课堂首页和搜索结果页,操作图示如下:

1:腾讯课堂首页

2:搜索结果页面

使用webdirver的api完成模拟上述步骤代码如下:

SearchCase.java

  1. 1 package com.lemon.auto.po;
  2. 2
  3. 3 import org.openqa.selenium.By;
  4. 4 import org.openqa.selenium.WebDriver;
  5. 5 import org.openqa.selenium.firefox.FirefoxDriver;
  6. 6
  7. 7 public class SearchCase {
  8. 8
  9. 9 public static void main(String[] args) {
  10. 10 //设置火狐的可执行文件的路径
  11. 11 System.setProperty("webdriver.firefox.bin", "D:/Program Files/Mozilla Firefox/firefox.exe");
  12. 12 //创建一个火狐驱动
  13. 13 WebDriver driver = new FirefoxDriver();
  14. 14
  15. 15 //1:打开腾讯课堂首页
  16. 16 driver.get("https://lemon.ke.qq.com");
  17. 17 //2:定位下拉图标,并点击
  18. 18 driver.findElement(By.cssSelector("i[class='icon-font i-v-bottom-small']")).click();
  19. 19 //3:定位课程或机构的下拉选择图标,并点击
  20. 20 driver.findElement(By.cssSelector("span[class='mod-search-dropdown-item']")).click();
  21. 21 //4:定位搜索输入框,并输入搜索内容“柠檬班”
  22. 22 driver.findElement(By.id("js_keyword")).sendKeys("柠檬班");
  23. 23 //5:定位搜索图标,并点击,进行搜索
  24. 24 driver.findElement(By.id("js_search")).click();
  25. 25 //6:获得机构名称
  26. 26 String agencyName = driver.findElement(By.cssSelector("h2[class='search-agency-name']")).getText();
  27. 27 System.out.println(agencyName);
  28. 28 //7:定位logo,并点击调整机构详情页面
  29. 29 driver.findElement(By.cssSelector("a[href='//lemon.ke.qq.com']")).click();
  30. 30
  31. 31 //关闭当前窗口
  32. 32 driver.close();
  33. 33 }
  34. 34 }

上述代码简单而清晰,但如果每个测试用例都这样去写的话,将会出现非常多的重复性代码,可维护性较低,因此,在使用Selenium WebDirver进行自动化开发时,可以使用po(页面对象)编程的思想,减少重复性代码、提高代码的可维护性。

一:po的概念与思想

po是page object的缩写,即页面对象。使用po是对页面进行抽象或者说建模的过程,需要把页面当作一个对象

面向对象编程语言中,进行面向对象编程需要考虑以下两点:

1:对象的属性(全局变量)

2:对象的行为(函数)

po思想也是一样,对页面进行抽象时,把页面的一个一个的web元素设计为页面对象的属性,把页面上的操作(如点击、输入等)设计为页面对象的行为

二:po中元素的定位

Selenium提供了许多注解和Api可以方便的定位元素和初始化元素,如下是腾讯课堂首页下拉选择机构图标的声明方式:

  1. 1 @FindBy(css="i[class='icon-font i-v-bottom-small']")
  2. 2 @CacheLookup
  3. 3 public WebElement select_icon;

三行代码释义:

1、@FindBy(css="i[class='icon-font i-v-bottom-small']")

指定了要元素的定位方式,如上表示以cssSelector方式进行定位,还有其他7种写法@FindBy(id="xxx")、@FindBy(name="xxx")...

2、@CacheLookup

表示缓存查找到元素,重复使用可提高查询速度

3、public WebElement select_icon;

声明一个web元素类型的全局变量

三:po中元素的初始化

Po提供了 PageFactory.initElements()来初始化页面元素,把查找的元素赋值到我们定义的属性(全局变量)上面

为了非常方便的进行页面元素的初始化,我们把该方法放置到页面类型的构造方法中,当调用该构造方法创建页面对象时,会调用该方法同时初始化页面的元素

代码如下:

  1. 1 public KeqqHomePage() {
  2. 2 PageFactory.initElements(driver, this);
  3. 3 }

四:页面行为抽象

元素初始化后,通过操作元素(如点击,输入)即可完成页面的功能,po中对页面功能的抽象,则提现为声明一个一个的对象方法

如下是页面选择机构的行为的抽象:

  1. 1 public void selectOrg(){
  2. 2 //选择机构需要进行两步操作,首先点击下拉图标,然后点击机构选项,
  3. 3 //两步操作写入到该方法,页面对象调用该对象方法,则可完成选择结构的行为
  4. 4 select_icon.click();
  5. 5 org_item.click();
  6. 6 }

下面是对“腾讯课堂首页”页面进行抽象的完整代码:

KeqqHomePage.java

  1. 1 package com.lemon.auto.po;
  2. 2 import org.openqa.selenium.WebElement;
  3. 3 import org.openqa.selenium.support.CacheLookup;
  4. 4 import org.openqa.selenium.support.FindBy;
  5. 5 import org.openqa.selenium.support.PageFactory;
  6. 6
  7. 7 /**
  8. 8 * 腾讯课堂首页类
  9. 9 * @author tommy
  10. 10 * @date 2018年5月11日
  11. 11 * @email
  12. 12 */
  13. 13 public class KeqqHomePage extends BasePage {
  14. 14 //下拉图标
  15. 15 @FindBy(css = "i[class='icon-font i-v-bottom-small']")
  16. 16 @CacheLookup //缓存元素,重复使用提高效率
  17. 17 public WebElement select_icon; //首页上选择图标
  18. 18
  19. 19 //机构元素
  20. 20 @FindBy(css = "span[class='mod-search-dropdown-item']")
  21. 21 @CacheLookup
  22. 22 public WebElement org_item;//结构选项
  23. 23
  24. 24 //输入框
  25. 25 @FindBy(id = "js_keyword")
  26. 26 @CacheLookup
  27. 27 public WebElement search_input;
  28. 28
  29. 29 //搜索按钮
  30. 30 @FindBy(id = "js_search")
  31. 31 @CacheLookup
  32. 32 public WebElement search_btn;
  33. 33
  34. 34 //页面的url
  35. 35 private static final String HOME_PAGE_URL = "https://ke.qq.com";
  36. 36
  37. 37 //打开首页
  38. 38 public void openUrl() {
  39. 39 driver.get(HOME_PAGE_URL);
  40. 40 }
  41. 41
  42. 42 /**
  43. 43 * 关闭浏览器
  44. 44 */
  45. 45 public void close() {
  46. 46 driver.quit();
  47. 47 }
  48. 48
  49. 49 //默认构造方法
  50. 50 public KeqqHomePage() {
  51. 51 //当前页面、当前对象
  52. 52 PageFactory.initElements(driver, this);
  53. 53 }
  54. 54
  55. 55 //2:方法(行为)
  56. 56 /**
  57. 57 * 选择机构
  58. 58 */
  59. 59 public void selectOrg() {
  60. 60 //选择机构需要进行什么操作
  61. 61 select_icon.click();
  62. 62 org_item.click();
  63. 63 }
  64. 64
  65. 65 /**
  66. 66 * 输入内容并且搜索---》返回一个结果页面
  67. 67 */
  68. 68 public SearchResultPage typeContentAndSearch(String content) {
  69. 69 //输入框输入内容
  70. 70 search_input.sendKeys(content);
  71. 71 //搜索按钮点击
  72. 72 search_btn.click();
  73. 73 return new SearchResultPage();
  74. 74 }
  75. 75 }

其中继承的父类BasePage仅仅只包含一个静态全局变量driver,方便其他页面继承直接使用

BasePage.java

  1. 1 package com.lemon.auto.po;
  2. 2 import org.openqa.selenium.WebDriver;
  3. 3 import com.lemon.auto.BrowerSelector;
  4. 4
  5. 5 public class BasePage {
  6. 6 //全局的webdirver
  7. 7 protected static WebDriver driver = BrowerSelector.getWebDriver();
  8. 8 }

其中BrowerSelector.getWebDriver()方法是封装好的一个工具类,用来启动浏览器,得到driver对象用的,在后面的源代码网盘链接中可以下载到。

相同的方式对“结果页面”进行抽象,代码如下:

SearchResultPage.java

  1. 1 package com.lemon.auto.po;
  2. 2
  3. 3 import org.openqa.selenium.WebElement;
  4. 4 import org.openqa.selenium.support.CacheLookup;
  5. 5 import org.openqa.selenium.support.FindBy;
  6. 6 import org.openqa.selenium.support.PageFactory;
  7. 7
  8. 8 public class SearchResultPage extends BasePage {
  9. 9
  10. 10 //logo图标
  11. 11 @FindBy(css = "a[href='//lemon.ke.qq.com']")
  12. 12 @CacheLookup
  13. 13 public WebElement logo_icon;
  14. 14
  15. 15 //机构名label
  16. 16 @FindBy(css = "h2[class='search-agency-name']")
  17. 17 @CacheLookup
  18. 18 public WebElement agency_name_label;
  19. 19
  20. 20 public SearchResultPage() {
  21. 21 PageFactory.initElements(driver, this);
  22. 22 }
  23. 23
  24. 24 /**
  25. 25 * 校验搜索结果
  26. 26 */
  27. 27 public void checkSearchResult() {
  28. 28 System.out.println(agency_name_label.getText());
  29. 29 }
  30. 30
  31. 31 /**
  32. 32 * 到机构的详情页面
  33. 33 */
  34. 34 public void toAgencyDetail() {
  35. 35 logo_icon.click();
  36. 36 }
  37. 37
  38. 38 }

执行测试的类,代码如下:

Tester.java

  1. 1 package com.lemon.auto.po;
  2. 2
  3. 3 public class Tester {
  4. 4
  5. 5 public static void main(String[] args) throws InterruptedException {
  6. 6 //1:打开腾讯课堂首页,创建页面对象模型
  7. 7 KeqqHomePage homePage = new KeqqHomePage();
  8. 8 homePage.openUrl();
  9. 9 //2:选择机构
  10. 10 homePage.selectOrg();
  11. 11 //3:输入内容并且点击搜索
  12. 12 SearchResultPage resultPage = homePage.typeContentAndSearch("柠檬班");
  13. 13 //4:检测结果
  14. 14 resultPage.checkSearchResult();
  15. 15 //5:到机构的详情页面、
  16. 16 resultPage.toAgencyDetail();
  17. 17 Thread.sleep(10000);
  18. 18 //关闭浏览器
  19. 19 homePage.close();
  20. 20 }
  21. 21 }

总结:

po编程,实质上就是分离页面元素、封装页面元素操作的过程,将可能变化的页面元素单独映射到对象属性、将页面元素操作抽象成函数,让我们以面向对象方式理解抽象一个页面,实际上就是编程中解耦思想的应用,从而简化测试用例的步骤,提高自动化测试代码的可维护性。

附公开课视频和源码百度云链接:

https://pan.baidu.com/s/1GoZyigdWiHIQY3xy9nE2ww 密码:1fgl

po编程——自动化测试面试必问的更多相关文章

  1. linux驱动工程面试必问知识点

    linux内核原理面试必问(由易到难) 简单型 1:linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些? 2:linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化, ...

  2. 互联网公司面试必问的mysql题目(下)

    这是mysql系列的下篇,上篇文章地址我附在文末. 什么是数据库索引?索引有哪几种类型?什么是最左前缀原则?索引算法有哪些?有什么区别? 索引是对数据库表中一列或多列的值进行排序的一种结构.一个非常恰 ...

  3. 互联网公司面试必问的Redis题目

    Redis是一个非常火的非关系型数据库,火到什么程度呢?只要是一个互联网公司都会使用到.Redis相关的问题可以说是面试必问的,下面我从个人当面试官的经验,总结几个必须要掌握的知识点. 介绍:Redi ...

  4. 【面试必问】python实例方法、类方法@classmethod、静态方法@staticmethod和属性方法@property区别

    [面试必问]python实例方法.类方法@classmethod.静态方法@staticmethod和属性方法@property区别 1.#类方法@classmethod,只能访问类变量,不能访问实例 ...

  5. 互联网公司面试必问的mysql题目(上)

    又到了招聘的旺季,被要求准备些社招.校招的题库.(如果你是应届生,尤其是东北的某大学,绝对福利哦) 介绍:MySQL是一个关系型数据库管理系统,目前属于 Oracle 旗下产品.虽然单机性能比不上or ...

  6. 面试必问:JVM类加载机制详细解析

    前言 在Java面试中,简历上有写JVM(Java虚拟机)相关的东西,JVM的类加载机制基本是面试必问的知识点. 类的加载和卸载 JVM是虚拟机的一种,它的指令集语言是字节码,字节码构成的文件是cla ...

  7. 一线大厂Java面试必问的2大类Tomcat调优

    一.前言 最近整理了 Tomcat 调优这块,基本上面试必问,于是就花了点时间去搜集一下 Tomcat 调优都调了些什么,先记录一下调优手段,更多详细的原理和实现以后用到时候再来补充记录,下面就来介绍 ...

  8. python笔记39-unittest框架如何将上个接口的返回结果给下个接口适用(面试必问)

    前言 面试必问:如何将上个接口的返回结果,作为下个接口的请求入参?使用unittest框架写用例时,如何将用例a的结果,给用例b使用. unittest框架的每个用例都是独立的,测试数据共享的话,需设 ...

  9. 高级测试工程师面试必问面试基础整理——python基础(一)(首发公众号:子安之路)

    现在深圳市场行情,高级测试工程师因为都需要对编程语言有较高的要求,但是大部分又没有python笔试机试题,所以面试必问python基础,这里我整理一下python基本概念,陆续收集到面试中python ...

随机推荐

  1. 在 ns-3.25中添加 plc(电力线载波) 模块

    上一篇安装好了 ns-3.25,这里继续往里添加 plc 模块.整理之前现推荐一个网站,大家可以参考. 英属哥伦比亚大学(University of British Columbia,UBC)提供NS ...

  2. 优化之XML组件

    可在XML Parser 组件和XML Source定义中删除非project group,因为不需为这些非project group分配内存,但需要维护主键外键约束 ________________ ...

  3. 利用U盘安装win2008r2系统的步骤

    我们在公司或者家里,经常要安装各种系统,最近公司需要重新安装win2008r2系统.折腾了一天的时间,终于把系统装好了.将安装的步骤记录下来,方便大家查看,自己也做个记录. 1 准备win2008r2 ...

  4. BBS论坛(八)

    8.1.发送邮箱验证码功能 (1)cms/resetemail.html {% from 'common/_macros.html' import static %} {% block head %} ...

  5. laravel的消息队列剖析

    laravel的消息队列剖析 这篇来自于看到朋友转的58沈剑的一篇文章:1分钟实现"延迟消息"功能 在实际工作中也不止遇见过一次这个问题,我在想着以前是怎么处理的呢?我记得当初在上 ...

  6. uWSGI 踩坑记

    一.协议的一致性 uWSGI 是在 nginx 后面,所以 nginx 转发请求时的协议要和 uWSGI 监听的协议一致.否则就会出现问题,因为是三者之间的通信,排查起来需要想清楚请求传递的次序: N ...

  7. 前端笔记之JavaScript(七)深入函数&DOM那点事

    一.函数补充 1.1 arguments类数组对象 arguments 是一个对应于传递给函数的参数的类数组对象. 在函数中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们. ...

  8. ReentrantLock学习

    对于并发工作,你需要某种方式来防止两个任务访问相同的资源,至少在关键阶段不能出现这种冲突情况.防止这种冲突的方法就是当资源被一个任务使用时,在其上加锁.在前面的文章--synchronized学习中, ...

  9. centos6.5-vsftp搭建

    我的机子是默认是没有的vsftp. yum install -y vsftp 创建账户专为ftp而生.useradd ftp01 更改账户不可登录系统.usermod -s /sbin/nologin ...

  10. docker 复制镜像和复制容器

    复制镜像和复制容器都是通过保存为新镜像而进行的. 具体为: 保存镜像 docker save ID > xxx.tar docker load < xxx.tar 保存容器 docker ...