美文网首页
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()
    

    相关文章

      网友评论

          本文标题:PageObject设计模式

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