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基于smtplib实现异步发送邮件服务
May 28 Python
基于python的Tkinter实现一个简易计算器
Dec 31 Python
Python实现通过文件路径获取文件hash值的方法
Apr 29 Python
Python md5与sha1加密算法用法分析
Jul 14 Python
python numpy 一维数组转变为多维数组的实例
Jul 02 Python
Python中实例化class的执行顺序示例详解
Oct 14 Python
python 实现selenium断言和验证的方法
Feb 13 Python
将string类型的数据类型转换为spark rdd时报错的解决方法
Feb 18 Python
python 利用文件锁单例执行脚本的方法
Feb 19 Python
浅谈pytorch 模型 .pt, .pth, .pkl的区别及模型保存方式
May 25 Python
对Keras中predict()方法和predict_classes()方法的区别说明
Jun 09 Python
Python Matplotlib绘制动画的代码详解
May 30 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
PHP4引用文件语句的对比
2006/10/09 PHP
PHP字符过滤函数去除字符串最后一个逗号(rtrim)
2013/03/26 PHP
PHP中spl_autoload_register函数的用法总结
2013/11/07 PHP
php使用百度翻译api示例分享
2014/01/31 PHP
php中getservbyport与getservbyname函数用法实例
2014/11/18 PHP
php bootstrap实现简单登录
2016/03/08 PHP
IIS 7.5 asp Session超时时间设置方法
2017/04/17 PHP
php统计数组不同元素的个数的实例方法
2019/09/26 PHP
基于JQuery的一个简单的鼠标跟随提示效果
2010/09/23 Javascript
jquery分页插件AmSetPager(自写)
2013/04/15 Javascript
火狐下table中创建form导致两个table之间出现空白
2013/09/02 Javascript
JavaScript函数详解
2014/11/17 Javascript
JavaScript中Function详解
2015/02/27 Javascript
JS控制表格实现一条光线流动分割行的方法
2015/03/09 Javascript
详解Vue 非父子组件通信方法(非Vuex)
2017/05/24 Javascript
聊聊JS动画库 Velocity.js的使用
2018/03/13 Javascript
关于微信小程序bug记录与解决方法
2018/08/15 Javascript
Python 详解基本语法_函数_返回值
2017/01/22 Python
python difflib模块示例讲解
2017/09/13 Python
利用python实现简单的邮件发送客户端示例
2017/12/23 Python
使用Python AIML搭建聊天机器人的方法示例
2018/07/09 Python
Python文件读写常见用法总结
2019/02/22 Python
pyqt5移动鼠标显示坐标的方法
2019/06/21 Python
Django框架配置mysql数据库实现过程
2020/04/22 Python
python 实现aes256加密
2020/11/27 Python
伦敦高级内衣品牌:Agent Provocateur(大内密探)
2016/08/23 全球购物
实现strstr功能,即在父串中寻找子串首次出现的位置
2016/08/05 面试题
经典c++面试题二
2015/08/14 面试题
营业员实习自我鉴定
2013/12/07 职场文书
新郎新娘婚礼答谢词
2014/01/11 职场文书
怎样拟定创业计划书
2014/05/01 职场文书
爱国主义演讲稿
2014/05/07 职场文书
消防标语大全
2014/06/07 职场文书
活动主持人开场白
2015/05/28 职场文书
2016教师国培研修感言
2015/12/08 职场文书
创业项目大全(适合在家创业的项目)
2019/08/15 职场文书