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中urllib2模块的8个使用细节分享
Jan 01 Python
python中self原理实例分析
Apr 30 Python
理论讲解python多进程并发编程
Feb 09 Python
对Python中type打开文件的方式介绍
Apr 28 Python
python3中os.path模块下常用的用法总结【推荐】
Sep 16 Python
python可视化实现代码
Jan 15 Python
如何在Django中添加没有微秒的 DateTimeField 属性详解
Jan 30 Python
python单向链表的基本实现与使用方法【定义、遍历、添加、删除、查找等】
Oct 24 Python
python向图片里添加文字
Nov 26 Python
Spring Boot中使用IntelliJ IDEA插件EasyCode一键生成代码详细方法
Mar 20 Python
PyCharm 2020 激活到 2100 年的教程
Mar 25 Python
Python猫眼电影最近上映的电影票房信息
Sep 18 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
DOTA2 无惧惊涛骇浪 昆卡大型水友攻略
2020/04/20 DOTA
PHP实现文件上传功能实例代码
2017/05/18 PHP
PHP使用redis消息队列发布微博的方法示例
2017/06/22 PHP
PHP支付宝当面付2.0代码
2018/12/21 PHP
PHP实现网站应用微信登录功能详解
2019/04/11 PHP
jquery对表单操作2
2011/04/06 Javascript
jquery获取div宽度的实现思路与代码
2013/01/13 Javascript
使用indexOf等在JavaScript的数组中进行元素查找和替换
2013/09/18 Javascript
jQuery如何实现点击页面获得当前点击元素的id或其他信息
2014/01/09 Javascript
javascript实现获取cookie过期时间的变通方法
2014/08/14 Javascript
jQuery使用之处理页面元素用法实例
2015/01/19 Javascript
Sublime Text 3常用插件及安装方法
2015/12/16 Javascript
JS常用知识点整理
2017/01/21 Javascript
js实现适合新闻类图片的轮播效果
2017/02/05 Javascript
Vue中父组件向子组件通信的方法
2017/07/11 Javascript
Vue + Vue-router 同名路由切换数据不更新的方法
2017/11/20 Javascript
Angular ng-animate和ng-cookies用法详解
2018/04/18 Javascript
Vue数组响应式操作及高阶函数使用代码详解
2020/08/01 Javascript
[48:32]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 LGD vs VG
2018/04/01 DOTA
[02:07]2018DOTA2亚洲邀请赛主赛事第三日五佳镜头 fy极限反杀
2018/04/06 DOTA
python 正则式使用心得
2009/05/07 Python
Python读写及备份oracle数据库操作示例
2018/05/17 Python
在python下读取并展示raw格式的图片实例
2019/01/24 Python
使用python实现回文数的四种方法小结
2019/11/24 Python
Python:type、object、class与内置类型实例
2019/12/25 Python
男女钓鱼靴和甲板鞋:XTRATUF
2021/01/09 全球购物
道路建设实施方案
2014/03/18 职场文书
竞聘上岗演讲
2014/05/19 职场文书
基层党员四风问题自我剖析材料
2014/09/29 职场文书
民事代理词范文
2015/05/25 职场文书
无婚姻登记记录证明
2015/06/18 职场文书
2015暑期爱心支教策划书
2015/07/14 职场文书
师德师风培训感言
2015/08/03 职场文书
放假通知怎么写
2015/08/18 职场文书
Java实现多文件上传功能
2021/06/30 Java/Android
MySQL千万级数据表的优化实战记录
2021/08/04 MySQL