(一) 前言

简单的说就是分为2层,页面class 和测试class。

页面class:分为父类和子类(子类指具体的页面,每一个页面都创建一个类),父类中定义公有的属性和方法(操作)。

#对面向对象有了解的,应该很容易理解抽象出公有属性和方法的意思

#父类和子类我是按自己的理解进行描述的,或者可以说basepage对象(父对象,提供公有的属性、方法) 和 page对象(具体哪一个页面)

测试class:按照业务流程,对各个页面的属性、操作进行组合,形成一个测试用例。

使用page object模式,抽象出各个页面的元素、方法,然后再按照测试用例的要求进行组合。这样做的好处是

1、页面修改了,只要对页面类进行修改就好了,对测试类(测试用例)没太大影响

2、可以在多个测试复用部分代码。

3、测试代码(测试类、测试用例)部分变得更易读、灵活、可维护。

我把上一篇的代码按照page object模式修改了下,代码如下。

(二) 父类(BasePage对象,base.py)

 from abc import abstractclassmethod
class BasePage(object):
def __init__(self,driver):
self.driver = driver '''验证页面是否是指定的页面。
@abstractclassmethod修饰符指该方法是抽象的'''
@abstractclassmethod
def validate_page(self,driver):
return

(三) 首页(page对象(子类),homepage.py)

 from base import BasePage
class HomePage(BasePage):
#用来定位页面元素的ID、NAME、XPTH、CSS表达式等
_login_area = '#login_area'
_register = '注册' def validate_page(self,driver):
return driver.title == '博客园 - 开发者的网上家园'
#定位并点击 注册
def register_click(self):
self.login_area = self.driver.find_element_by_css_selector(self._login_area)
self.login_area.find_element_by_link_text(self._register).click()

(四) 注册页面(page对象(子类),registerpage.py)

 from base import BasePage
class RegisterPage(BasePage):
# 用来定位页面元素的ID、NAME、XPTH、CSS表达式等
_user_email = 'Email'
_user_phone_country = 'CountryCode'
_user_phone = 'PhoneNum'
_user_login_name = 'LoginName'
_user_nickname = 'DisplayName'
_user_password = 'Password'
_user_confirm_password = 'ConfirmPassword'
_phone_error = 'PhoneNum-error'
_loginName_error = 'LoginName-error' def validate_page(self,driver):
return driver.title == '用户注册 - 博客园' #输入注册信息
def send_keys(self,email,phone,login_name,nickname,password,confirm_password):
self.driver.find_element_by_id(self._user_email).clear()
self.driver.find_element_by_id(self._user_phone).clear()
self.driver.find_element_by_id(self._user_login_name).clear()
self.driver.find_element_by_id(self._user_nickname).clear()
self.driver.find_element_by_id(self._user_password).clear()
self.driver.find_element_by_id(self._user_confirm_password).clear()
self.driver.find_element_by_id(self._user_email).send_keys(email)
self.driver.find_element_by_id(self._user_phone).send_keys(phone)
self.driver.find_element_by_id(self._user_login_name).send_keys(login_name)
self.driver.find_element_by_id(self._user_nickname).send_keys(nickname)
self.driver.find_element_by_id(self._user_password).send_keys(password)
self.driver.find_element_by_id(self._user_confirm_password).send_keys(confirm_password) #手机号码有误时的提示信息
def phone_err(self):
phone_error = self.driver.find_element_by_id(self._phone_error)
return phone_error.text #登录名不合法时的提示信息
def loginName_error(self):
loginName_error = self.driver.find_element_by_id(self._loginName_error)
return loginName_error.text

(五)   测试类(测试用例,testRegisterNewUser.py)

 from selenium import webdriver
from ddt import ddt,data,unpack
import xlrd
from homepage import HomePage
from registerpage import RegisterPage
from basetestcase import BaseTestCase
#读取Excel数据的函数
def get_data(file_name):
rows = []
book = xlrd.open_workbook(file_name)
sheet = book.sheet_by_index(0)
for r_idx in range(1, sheet.nrows):
rows.append(list(sheet.row_values(r_idx,0)))
pthone = rows[r_idx - 1].pop(1)
rows[r_idx - 1].insert(1, str(int(pthone)))
return rows
@ddt
class RegisterNewUserDDT(BaseTestCase):
#重写setUpClass()
@classmethod
def setUpClass(cls):
cls.driver = webdriver.Chrome()
cls.driver.implicitly_wait(30)
cls.driver.maximize_window()
cls.driver.get('https://www.cnblogs.com/')
#创建HomePage()类的对象实例
home_page = HomePage(cls.driver)
home_page.register_click()
# 读取excel文件的数据作为参数
@data(*get_data('data/reTest.xlsx'))
@unpack
def test_register_new_user(self,email,phone,login_name,nickname,password,confirm_password,expected_result):
#创建RegisterPage()的对象实例
register_page = RegisterPage(self.driver)
self.assertTrue(register_page.validate_page(self.driver))
register_page.send_keys(email,phone,login_name,nickname,password,confirm_password)
if phone == '':
self.assertTrue(register_page.phone_err() == expected_result)
elif login_name == 'b':
self.assertTrue(register_page.loginName_error() == expected_result)

(六) 测试准备(basetestcase.py)

#这部分本来想放到第二步的,不过感觉有点影响对page object的理解,就放到最后了

  创建一个类,定义setup()和teardowm()方法,方便所有测试复用。这个类可以理解为是测试类的一部分,我只是把所有测试类(测试用例)都用到的setup()和teardowm()拿出来,方便复用。如果哪个测试用例有特殊要求,也可以重写。

 import unittest
from selenium import webdriver class BaseTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.driver = webdriver.Chrome()
cls.driver.implicitly_wait(30)
cls.driver.maximize_window()
cls.driver.get('https://www.cnblogs.com/')
@classmethod
def tearDownClass(cls):
cls.driver.quit()

Python+Selenium笔记(十三):Page Object设计模式的更多相关文章

  1. python+ selenium&APPium自动化 page Object 设计模式

    题记: 之前公司项目比较稳定, 在进行了系统测试,想用自动化测试进行冒烟测试,或者对主要功能进行测试, 因此用到了PO模式 因此做个记录: Page Object Page Object模式是使用Se ...

  2. Python+Selenium框架设计--- Page Object Model

    POM(Page Object Model):页面对象模型,POM是一种最近几年非常流行的自动化测试模型,或者思想,POM不是一个框架,就是一个解决问题的思想.采用POM的目的,是为了解决前端中UI变 ...

  3. selenium+Python(Page Object 设计模式实例)

    以下实例演示了采用了page Object设计模式的方式登录qq空间: 1.创建基础类page:在初始方法__init__()定义驱动的(driver),基本url(base_url)和超时时间(ti ...

  4. Python+selenium之Page Object设计模式

    Page Object是selenium自动化测试项目开发实践的最佳设计模式之一,他主要提现在对界面交互细节的封装,这样可以使测试案例隔你给加关注于业务而非界面细节,从而提高测试案例的可读性. Pag ...

  5. web端自动化——selenium Page Object设计模式

    Page Object设计模式的优点如下: ①    减少代码的重复. ②    提高测试用例的可读性. ③    提高测试用例的可维护性,特别是针对UI频繁变化的项目. 当为Web页面编写测试时,需 ...

  6. Selenium+java - Page Object设计模式

    前言 Page Object(页面对象)模式,是Selenium实战中最为流行,并且被自动化测试同学所熟悉和推崇的一种设计模式之一.在设计测试时,把页面元素定位和元素操作方法按照页面抽象出来,分离成一 ...

  7. Selenium(十九):unittest单元测试框架(五) Page Object设计模式

    1. Page Object设计模式 Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一,它主要体现在对界面交互细节的封装,这样可以使测试方案更关注于业务而非界面细节.从 ...

  8. Selenium 2自动化测试实战39(Page Object设计模式)

    Page Object设计模式 Page object是selenium自动化测试项目开发时间的最佳设计模式之一,主要体现在对界面交互细节的封装. 1.认识page object优点如下:1.减少代码 ...

  9. Page Object设计模式实践

    Page Object模式是使用Selenium的广大同行最为公认的一种设计模式.在设计测试时,把元素和方法按照页面抽象出来,分离成一定的对象,然后再进行组织. Page Object模式,创建一个对 ...

  10. Page Object 设计模式介绍

    Page Object 是 Selenium 自动化测试项目开发实践的最佳设计模式之一,Page Object 的主要体现于对界面交互细节的封装,这样可以使测试案例更关注与业务而非界面细节,提高测试案 ...

随机推荐

  1. Linux 部署 ASP.NET Core 的一些问题记录

    异常错误: 关闭 IP6 #修改 vi /etc/sysctl.conf # 添加如下三条设置    net.ipv6.conf.all.disable_ipv6 = 1    net.ipv6.co ...

  2. JavaScript -- Window-Scroll

    -----037-Window-Scroll.html----- <!DOCTYPE html> <html> <head> <meta http-equiv ...

  3. JavaScript -- Window-Move,Print

    -----035-Window-Move.html----- <!DOCTYPE html> <html> <head> <meta http-equiv=& ...

  4. CFileDialog类的详情

    CFileDialog类封装了Windows常用的文件对话框. 常用的文件对话框提供了一种简单的与Windows标准相一致的文件打开和文件存盘对话框功能. void CnotepadDlg::OnOp ...

  5. java多线程下的所的概念

    锁和synchronized关键字     为了同步多线程,Java语言使用监视器(monitors),一种高级的机制来限定某一 时刻只有一个线程执行一段受监视器保护的代码.监视器的行为是通过锁来实现 ...

  6. 32-hadoop-hbase调优

    1, 数据膨胀后, 才对region进行分区, 效率比较低, 所以需要预创建region, 进行负载均衡写入 package com.wenbronk.hbase; import org.apache ...

  7. [Python学习笔记-003] 使用PyOTP获取基于OTOP算法的动态口令

    建立安全的VPN连接,不仅需要输入用户名和密码,还需要输入动态口令(token).作为一个懒人,我更喜欢什么手工输入都不需要,既不需要输入password,也不需要输入token.也就是说,只需一个命 ...

  8. 【转】Java中堆和栈的区别

    Java的堆是一个运行时数据区,类的对象从中分配空间.这些对象通过new.newarray.anewarray和multianewarray等 指令建立,它们不需要程序代码来显式的释放.堆是由垃圾回收 ...

  9. 微信emoji的code

    const MAP = [        "\xc2\xa9" => 'COPYRIGHT SIGN',        "\xc2\xae" => ...

  10. es6学习笔记3--解构和对象

    1.解构 在接收数据的地方(比如赋值的左边),解构使你使用模式去获取部分数据. 下面的代码是解构的一个例子: let obj = { first: 'Jane', last: 'Doe' }; let ...