美文网首页
PageObject设计模式

PageObject设计模式

作者: 清水秋香 | 来源:发表于2020-02-23 23:24 被阅读0次
  • PO设计原理:
    将页面封装成对象
    页面对象内封装业务方法
    元素定位方法可存放到其他配置文件


    PO.png

    PO设计是一种思想,任何UI自动化测试都可以套用这种思想,不仅限于selenium的webUI模式

PO设计规范
  • 页面对象化
    1.每个页面封装成对象
    例如:登录页面可以设计成LoginPage类
    2.封装具体业务方法
    例如:登陆页面的登陆方法有 login(username,password)
    3.不保存具体的元素定位
    例如:定位用户名和密码框的表达式不写在代码里,放在外部配置文件当中

  • 页面元素属性化
    1.只涉及到要操作的元素名称
    2.具体的定位方式方法不写在代码里

  • 元素定位可配置化
    1.配置以键值对形式存在
    2.区分出不同的页面
    3.保存元素配置的文件形式没有限制文本文件、excel、数据库等

页面类的设计
  • 页面类的层级抽象
    1.构造页面对象
    创建页面基类,封装基本操作方法,由其他业务类继承
    2.封装相关业务方法
    业务页面对象中封装常用的业务操作
    3.抽取元素定位
    抽取具体的元素定位方法存放到配置文件
    4.测试案例构成
    结合页面对象编写具体的业务流

  • Yaml格式配置文件特点
    1.YAML 的数据组织主要依赖的是空白,缩进,分行等结构,可读性好。
    2.YAML 实现简单,解析成本很低,和脚本语言的交互性好。
    3.YAML 使用实现语言的数据类型
    4.YAML 表达能力强,扩展性好
    5.安装方法 --pip install pyyaml

书写PO模式建议:
1.先写出具体的业务逻辑--比如登录
2.再将写好的逻辑封装到类里面
3.继续构造其他的页面类
4.将这些类共同的功能抽象化父类,被其他业务类继承
5.可以将代码内部的具体元素抽离出来用外部的配置文件进行管理

  • base类:封装元素定位方法
from selenium.webdriver.support.select import Select
class BasePage:
    def __init__(self,driver):
        # 这里driver要传进来,如果不传进来直接用webdriver赋值,有多个页面继承base类会导致打开多个页面,使用的不是同一个浏览器对象
        self.driver = driver
        self.driver.implicitly_wait(10)

    def click_element(self, locator):
        self.driver.find_element(locator[0], locator[1]).click()

    def input_text(self, locator, text):
        self.driver.find_element(locator[0], locator[1]).clear()
        self.driver.find_element(locator[0], locator[1]).send_keys(text)

    def find_elements(self, locator):
        # 如果不return返回的是空
        return self.driver.find_elements(locator[0], locator[1])

    def find_element(self,locator):
        return self.driver.find_element(locator[0],locator[1])

    def find_select(self,locator,text):
        ele = Select(self.find_element(locator))
        ele.select_by_visible_text(text)
  • 页面类:封装各个页面
from selenium import webdriver
import time

from basepage import BasePage

from conf_util import get_locators

class LoginPage(BasePage):
    def __init__(self, driver):
        BasePage.__init__(self, driver)
        self.driver.get('http://localhost/mgr/login/login.html')
        LoginPage = get_locators('locator.yml')['LoginPage']
        self.username_input = LoginPage['username']
        self.password_input = LoginPage['password']
        self.login_btn = LoginPage['login_btn']

    def login(self, username, password):
        self.input_text(self.username_input, username)
        self.input_text(self.password_input, password)
        self.click_element(self.login_btn)
        # 返回下一个流程的页面
        return CoursePage(self.driver)

class CoursePage(BasePage):
    def __init__(self, driver):
        BasePage.__init__(self, driver)
        CoursePage = get_locators('locator.yml')['Coursepage']
        self.addCourseBtn = CoursePage['addCourseBtn']
        self.courseName = CoursePage['courseName']
        self.courseDesc = CoursePage['courseDesc']
        self.courseIdx = CoursePage['courseIdx']
        self.createBtn = CoursePage['createBtn']
        self.confirmBtn = CoursePage['confirmBtn']
        self.delBtns = CoursePage['delBtns']
        self.courseBtn = CoursePage['courseBtn']
    def add_Course(self, name, dec, idx):
        self.click_element(self.courseBtn)
        # 点击添加课程
        self.click_element(self.addCourseBtn)
        # 输入课程名称
        self.input_text(self.courseName, name)
        # 输入课程描述
        self.input_text(self.courseDesc, dec)
        # 输入展示次序
        self.input_text(self.courseIdx, idx)
        # 点击创建
        self.click_element(self.createBtn)

    def delete_allCourse(self):
        self.click_element(self.courseBtn)
        self.driver.implicitly_wait(1)
        while True:

            delBtns = self.find_elements(self.delBtns)
            if not delBtns:  # 课程全部删除,删除按钮没有了
                break
            # 删除课程的具体过程
            # time.sleep(1)
            delBtns[0].click()  # 每次删除第一个课程
            time.sleep(1)
            self.click_element(self.confirmBtn)
            time.sleep(1)  # 给弹出框消失的时间,防止点击下面的删除按钮点不到
        self.driver.implicitly_wait(10)

    # 此方法防止如果不是从登录界面进入课程页面,好比从课时页面到课程页面
    def get_coursePage(self):
        # 确保浏览器访问页面
        self.driver.get('http://localhost/mgr/ps/mgr/index.html#/')
        # 返回这个页面对象
        return self

    def driverquit(self):
        self.driver.quit()


class TeacherPage(BasePage):
    def __init__(self, driver):
        BasePage.__init__(self, driver)
        TeacherPage = get_locators('locator.yml')['TeacherPage']
        self.clickToAdd = TeacherPage['clickToAdd']
        self.actualName = TeacherPage['actualName']
        self.loginName = TeacherPage['loginName']
        self.desc = TeacherPage['desc']
        self.idx = TeacherPage['idx']
        self.selectCourse = TeacherPage['selectCourse']
        #老师页面
        self.teacherMenu = TeacherPage['teacherMenu']
        self.clickAddCourse = TeacherPage['clickAddCourse']
        self.determine = TeacherPage['determine']
        self.check = TeacherPage['check']
        self.delectTeacher = TeacherPage['delectTeacher']
        #删除确定
        self.sureToDelete = TeacherPage['sureToDelete']
    def add_teacher(self,actualName,loginName,desc,idx,course):

        self.click_element(self.teacherMenu)
        time.sleep(3)
        # 点击添加老师
        self.click_element(self.clickToAdd)
        # 输入老师姓名
        self.input_text(self.actualName,actualName)
        # 输入登录名
        self.input_text(self.loginName,loginName)
        # 输入描述
        self.input_text(self.desc,desc)
        # 输入次序
        self.input_text(self.idx,idx)
        # 选择授课信息
        self.find_select(self.selectCourse,course)
        # 点击加号
        self.click_element(self.clickAddCourse)
        #点击确定
        self.click_element(self.determine)

        # 校验老师是否添加成功
        assert actualName in [name.text for name in self.find_elements(self.check)], '老师添加失败'

    # 删除所有老师用于初始化环境
    def delete_teacher(self):
        self.click_element(self.teacherMenu)
        self.driver.implicitly_wait(1)
        while True:
            delBtns = self.find_elements(self.delectTeacher)
            if not delBtns:  # 课程全部删除,删除按钮没有了
                break
            # 删除课程的具体过程
            # time.sleep(1)
            delBtns[0].click()  # 每次删除第一个课程
            time.sleep(1)
            self.click_element(self.sureToDelete)
            time.sleep(1)  # 给弹出框消失的时间,防止点击下面的删除按钮点不到
        self.driver.implicitly_wait(10)

-Yaml 文件存储个页面的具体定位方式

LoginPage:
  username: ['id', 'username']
  password: ['id', 'password']
  login_btn: ['css selector', '[class="btn btn-success"]']

Coursepage:
  addCourseBtn: ['css selector', '[ng-click="showAddOne=true"]']
  courseName: ['css selector', '[ng-model="addData.name"]']
  courseDesc: ['css selector', '[ng-model="addData.desc"]']
  courseIdx: ['css selector', '[ng-model="addData.display_idx"]']
  createBtn: ['css selector', '[ng-click="addOne()"]']
  confirmBtn: ['css selector', '.btn-primary']
  delBtns: ['css selector', '[ng-click="delOne(one)"]']
  courseBtn: ['css selector','a[ui-sref="course"]']

TeacherPage:
  clickToAdd: ['css selector','[ng-click="showAddOne=true"]']
  actualName: ['css selector','input[ng-model="addEditData.realname"]']
  loginName: ['css selector','input[ng-model="addEditData.username"]']
  desc: ['css selector','textarea[ng-model="addEditData.desc"]']
  idx: ['css selector','input[ng-model="addEditData.display_idx"]']
  selectCourse: ['css selector','select[ng-model="$parent.courseSelected"]']
  teacherMenu: ['css selector','a[ui-sref="teacher"]']
  clickAddCourse: ['css selector','i[class="fa fa-plus"]']
  determine: ['css selector','[ng-click="addOne()"]']
  check: ['css selector','tr.ng-scope td:nth-of-type(2)']
  delectTeacher: ['css selector','button[ng-click="delOne(one)"]']
  sureToDelete: ['css selector','[class="btn btn-primary"]']
  • 此文件用于读取yaml文件并加载
import yaml
yaml.warnings({'YAMLLoadWarning':False})

def get_locators(yamlfile):
    with open(yamlfile, 'r') as f:
        f = f.read()
        #载入读取文本
        res = yaml.load(f)
        return res
  • unittest 添加测试项
import unittest
from selenium import webdriver
from page import TeacherPage,LoginPage

class webtest(unittest.TestCase):
    def setUp(self):
        driver = webdriver.Chrome()
        self.lp = LoginPage(driver)
        self.tp = TeacherPage(driver)
        self.cp = self.lp.login('xxoo', 'xxoo')
        self.cp.delete_allCourse()
        self.cp.add_Course('初中化学', '课程描述', 2)
        self.tp.delete_teacher()
    def test(self):
        self.tp.add_teacher('隔壁老王', '嘿咻', '嘿嘿咻咻', 3, '活塞运动学')

    def tearDown(self):
        self.cp.delete_allCourse()
        self.cp.driverquit()
if __name__ == '__main__':
    unittest.main()

相关文章

  • 如何使用Page Object 设计模型

    什么是 PageObject 设计模型? PageObject 设计模型是在自动化测试过程中普遍采用的一种设计模式...

  • PageObject设计模式

    PO设计原理:将页面封装成对象页面对象内封装业务方法元素定位方法可存放到其他配置文件PO.pngPO设计是一种思想...

  • PO设计模式

    1 PO设计模式 什么是设计模式? PO(PageObject)设计模式将某个页面的所有元素对象定位和对元素对象的...

  • PageObject设计模式(appium)

    PO设计原理:将页面封装成对象页面对象内封装业务方法元素定位方法可存放到其他配置文件PO.pngPO设计是一种思想...

  • PageObject设计模式简介

  • 20170810自动化测试设计

    PageObject模式是Selenium中的一种测试设计模式,主要是将每一个页面设计为一个Class,其中包含页...

  • PageObject模式

    PageObject的核心思想是封装:把页面常用服务封装成函数 封装的好处是复用、逻辑清晰 1.公共方法一定要代表...

  • 动态代理的魔法-@FindBy的工作原理

    背景简介 由于Selenium框架采用PageObject设计模式,因而提供提供了不少很方便的注解来达到目的,其中...

  • 2018-02-06 PageObject的一个小窍门

    在使用pageObject设计模式测试页面的时候难免会遇到frame的情况,此时一定要放亮眼睛,先switch_t...

  • 框架整体说明

    项目基于python+selenium+unittest框架搭建,基于pageobject模式编写,主要实现了下面...

网友评论

      本文标题:PageObject设计模式

      本文链接:https://www.haomeiwen.com/subject/zheeqhtx.html