Python+Selenium使用Page Object实现页面自动化测试


Posted in Python onJuly 14, 2019

  Page Object模式是Selenium中的一种测试设计模式,主要是将每一个页面设计为一个Class,其中包含页面中需要测试的元素(按钮,输入框,标题 等),这样在Selenium测试页面中可以通过调用页面类来获取页面元素,这样巧妙的避免了当页面元素id或者位置变化时,需要改测试页面代码的情况。 当页面元素id变化时,只需要更改测试页Class中页面的属性即可。

    Page Object模式是一种自动化测试设计模式,将页面定位和业务操作分开,分离测试对象(元素对象)和测试脚本(用例脚本),提高用例的可维护性。

    unittest是一种单元测试框架,用于设计各式各样的测试用例,可调用PageObject设计的页面类(对象),设计出更加可维护的用例。它提供用例组织与执行,提供丰富的比较(断言)方法,提供丰富的日志,统一适用于web自动化用例的开发与执行。

使用PO模式设计思路如下:

1.定义页面基础类,封装所有页面公用的方法。

命名为test_8_3_2_BasePage.py

# coding=utf-8
'''
Created on 2016-8-13
@author: Jennifer
Project:基础类BasePage,封装所有页面都公用的方法,
定义open函数,重定义find_element,switch_frame,send_keys等函数。
在初始化方法中定义驱动driver,基本url,title
WebDriverWait提供了显式等待方式。
'''
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class BasePage(object):
  """
  BasePage封装所有页面都公用的方法,例如driver, url ,FindElement等
  """
  #初始化driver、url、pagetitle等
  #实例化BasePage类时,最先执行的就是__init__方法,该方法的入参,其实就是BasePage类的入参。
  #__init__方法不能有返回值,只能返回None
  #self只实例本身,相较于类Page而言。
  def __init__(self, selenium_driver, base_url, pagetitle):
    self.driver = selenium_driver
    self.base_url = base_url
    self.pagetitle = pagetitle
     
  #通过title断言进入的页面是否正确。
  #使用title获取当前窗口title,检查输入的title是否在当前title中,返回比较结果(True 或 False)
  def on_page(self, pagetitle):
    return pagetitle in self.driver.title
  
  #打开页面,并校验页面链接是否加载正确
  #以单下划线_开头的方法,在使用import *时,该方法不会被导入,保证该方法为类私有的。
  def _open(self, url, pagetitle):
    #使用get打开访问链接地址
    self.driver.get(url)
    self.driver.maximize_window()
    #使用assert进行校验,打开的窗口title是否与配置的title一致。调用on_page()方法
    assert self.on_page(pagetitle), u"打开开页面失败 %s"%url
  
  #定义open方法,调用_open()进行打开链接
  def open(self):
    self._open(self.base_url, self.pagetitle)
  
  #重写元素定位方法
  def find_element(self,*loc):
#    return self.driver.find_element(*loc)
    try:
      #确保元素是可见的。
      #注意:以下入参为元组的元素,需要加*。Python存在这种特性,就是将入参放在元组里。
#      WebDriverWait(self.driver,10).until(lambda driver: driver.find_element(*loc).is_displayed())
      #注意:以下入参本身是元组,不需要加*
      WebDriverWait(self.driver,10).until(EC.visibility_of_element_located(loc))
      return self.driver.find_element(*loc)
    except:
      print u"%s 页面中未能找到 %s 元素"%(self, loc)
  
  #重写switch_frame方法
  def switch_frame(self, loc):
    return self.driver.switch_to_frame(loc)
  
  #定义script方法,用于执行js脚本,范围执行结果
  def script(self, src):
    self.driver.execute_script(src)
  
  #重写定义send_keys方法
  def send_keys(self, loc, vaule, clear_first=True, click_first=True):
    try:
      loc = getattr(self,"_%s"% loc) #getattr相当于实现self.loc
      if click_first:
        self.find_element(*loc).click()
      if clear_first:
        self.find_element(*loc).clear()
        self.find_element(*loc).send_keys(vaule)
    except AttributeError:
      print u"%s 页面中未能找到 %s 元素"%(self, loc)

2.定义登录页面的基本操作方法。

所有页面元素定位都在此层定义,UI一旦有更改,只需在修改这一层页面对象属性即可。

命名为test_8_3_2_LoginPage.py

# coding=utf-8
'''
Created on 2016-8-13
@author: Jennifer
Project:页面基本操作方法:如open,input_username,input_password,click_submit
'''
from selenium.webdriver.common.by import By
from test_8_3_2_BasePage import BasePage

#继承BasePage类
class LoginPage(BasePage):
  #定位器,通过元素属性定位元素对象
  username_loc =(By.NAME,'email')
  password_loc =(By.NAME,'password')
  submit_loc =(By.ID,'dologin')
  span_loc =(By.CSS_SELECTOR,"div.error-tt>p")
  dynpw_loc =(By.ID,"lbDynPw")
  userid_loc =(By.ID,"spnUid")
  
  #操作
  #通过继承覆盖(Overriding)方法:如果子类和父类的方法名相同,优先用子类自己的方法。
  #打开网页
  def open(self):
  #调用page中的_open打开连接
    self._open(self.base_url, self.pagetitle)
  
  #输入用户名:调用send_keys对象,输入用户名
  def input_username(self, username):
#    self.find_element(*self.username_loc).clear()
    self.find_element(*self.username_loc).send_keys(username)
  
  #输入密码:调用send_keys对象,输入密码
  def input_password(self, password):
#    self.find_element(*self.password_loc).clear()
    self.find_element(*self.password_loc).send_keys(password)
    
  #点击登录:调用send_keys对象,点击登录
  def click_submit(self):
    self.find_element(*self.submit_loc).click()
  
  #用户名或密码不合理是Tip框内容展示
  def show_span(self):
    return self.find_element(*self.span_loc).text
  
  #切换登录模式为动态密码登录(IE下有效)
  def swich_DynPw(self):
    self.find_element(*self.dynpw_loc).click()
  
  #登录成功页面中的用户ID查找
  def show_userid(self):
    return self.find_element(*self.userid_loc).text

3.使用unittest框架编写测试用例 

# coding=utf-8
'''
Created on 2016-8-13
@author: Jennifer
Project:使用unittest框架编写测试用例。
'''
import unittest 
from test_8_3_2_LoginPage import LoginPage
from selenium import webdriver

class Caselogin126mail(unittest.TestCase):
  """
     登录126邮箱的case
  """
  def setUp(self):
    self.driver = webdriver.Firefox()
    self.driver.implicitly_wait(30)
    self.url ="http://mail.126.com"
    self.username ="XXX"
    self.password ="XXX"
  
  #用例执行体
  def test_login_mail(self):
    #声明LoginPage类对象
    login_page = LoginPage(self.driver, self.url, u"网易")
    #调用打开页面组件
    login_page.open()
    #切换到登录框Frame
    login_page.switch_frame('x-URS-iframe')
    #调用用户名输入组件
    login_page.input_username(self.username)  
    #调用密码输入组件
    login_page.input_password(self.password)    
    #调用点击登录按钮组件
    login_page.click_submit()

  def tearDown(self):
    self.driver.quit()
    
if __name__ == "__main__":
  unittest.main()

结语:

这样分层的好处是,不同层关心不同的问题。页面对象层只关心元素定位问题,测试用例只关心测试的数据。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python基础教程之udp端口扫描
Feb 10 Python
跟老齐学Python之坑爹的字符编码
Sep 28 Python
简单介绍Python中用于求最小值的min()方法
May 15 Python
Python探索之SocketServer详解
Oct 28 Python
python 列表删除所有指定元素的方法
Apr 19 Python
10个Python面试常问的问题(小结)
Nov 20 Python
关于Python 中的时间处理包datetime和arrow的方法详解
Mar 19 Python
python上selenium的弹框操作实现
Jul 13 Python
python利用后缀表达式实现计算器功能
Feb 22 Python
python自动统计zabbix系统监控覆盖率的示例代码
Apr 03 Python
python中Tkinter 窗口之输入框和文本框的实现
Apr 12 Python
详解OpenCV曝光融合
Apr 29 Python
Python实现Selenium自动化Page模式
Jul 14 #Python
详解Selenium+PhantomJS+python简单实现爬虫的功能
Jul 14 #Python
python基于Selenium的web自动化框架
Jul 14 #Python
Django项目使用CircleCI的方法示例
Jul 14 #Python
Python实现最常见加密方式详解
Jul 13 #Python
python Pandas库基础分析之时间序列的处理详解
Jul 13 #Python
简单了解python反射机制的一些知识
Jul 13 #Python
You might like
mysql5的sql文件导入到mysql4的方法
2008/10/19 PHP
PHP正则提取不包含指定网址的图片地址的例子
2014/04/21 PHP
PHP封装的一个支持HTML、JS、PHP重定向的多功能跳转函数
2014/06/19 PHP
php使用fputcsv()函数csv文件读写数据的方法
2015/01/06 PHP
PHP实现防止表单重复提交功能【基于token验证】
2018/05/24 PHP
js CSS操作方法集合
2008/10/31 Javascript
10个基于浏览器的JavaScript调试工具分享
2013/02/07 Javascript
node.js中的socket.io的广播消息
2014/12/15 Javascript
javascript实现动态改变层大小的方法
2015/05/14 Javascript
深入理解JavaScript中的并行处理
2016/09/22 Javascript
JS实现控制图片显示大小的方法【图片等比例缩放功能】
2017/02/18 Javascript
JS仿QQ好友列表展开、收缩功能(第二篇)
2017/07/07 Javascript
js注册时输入合法性验证方法
2017/10/21 Javascript
node 使用 async 控制并发的方法
2018/05/07 Javascript
手把手教你vue-cli单页到多页应用的方法
2018/05/31 Javascript
通过JQuery,JQueryUI和Jsplumb实现拖拽模块
2019/06/18 jQuery
详解Vue 的异常处理机制
2020/11/30 Vue.js
[02:32]DOTA2英雄基础教程 祸乱之源
2013/12/23 DOTA
python3音乐播放器简单实现代码
2020/04/20 Python
在python中将字符串转为json对象并取值的方法
2018/12/31 Python
浅谈python编译pyc工程--导包问题解决
2019/03/20 Python
Python 利用Entrez库筛选下载PubMed文献摘要的示例
2020/11/24 Python
VSCode中autopep8无法运行问题解决方案(提示Error: Command failed,usage)
2021/03/02 Python
常用的HTML5列表标签
2017/06/20 HTML / CSS
毕业生求职的求职信
2013/12/05 职场文书
自动化专业毕业生求职信
2014/06/18 职场文书
工厂仓管员岗位职责范本
2014/07/17 职场文书
法人身份证明书
2014/10/08 职场文书
2015年档案管理员工作总结
2015/05/13 职场文书
单位考核鉴定意见
2015/06/05 职场文书
2016关于学习党章的心得体会
2016/01/15 职场文书
合理缓解职场压力,让你随时保持最佳状态!
2019/06/21 职场文书
redis实现共同好友的思路详解
2021/05/26 Redis
浅谈什么是SpringBoot异常处理自动配置的原理
2021/06/21 Java/Android
Nginx配置https的实现
2021/11/27 Servers
Java的Object类的九种方法
2022/04/13 Java/Android