• (十) web自动化测试-PO设计模式


    (十) web自动化测试-PO设计模式



    前言

    PO设计模式

    PO(page object)设计模式是在自动化测试中已经流行起来的一种易于维护和减少代码的设计模式. 在自动化测试中, PO对象作为一个与页面交互的接口. 测试中需要与页面的UI进行交互时, 便调用PO的方法. 这样做的好处是, 如果页面的UI发生了更改,那么测试用例本身不需要更改, 只需更改PO中的代码即可.

    PO设计模式具有以下优点:

    • 测试代码与页面的定位代码(如定位器或者其他的映射)相分离.
    • 该页面提供的方法或元素在一个独立的类中, 而不是将这些方法或元素分散在整个测试中.

    一、PageObject原则

    • 使用方法去代替页面的功能点
    • 不要过多暴露页面的细节
    • 封装PO本身不要有断言
    • 一个方法要返回另一个页面对象(涉及跳转时使用)
    • 不要为页面中的每一个功能都去进行封装,只封装重要的功能即可
    • 对于不同的结果,需要定义不同的方法

    1. 使用方法代替页面的功能点

    页面中通常有很多功能点,比如登录、注册、搜索等,在PO中定义方法来代替这些功能,在方法中定义功能的操作逻辑

    2. case中不要过多暴露页面的细节

    执行的case中,不要暴露操作的细节,通常是直接调用封装好的po中的方法,比如:

    def test_login(self):
    	self.index.gotologin()
    
    • 1
    • 2

    通常细节封装在po定义的方法中,不在测试用例中暴露,这样方便后续的维护,页面有变动时,只需要修改po中方法即可,测试断言相关部分不用修改

    3. po本身不进行断言

    在po定义的方法中不要进行断言操作,尽力保持页面逻辑和测试逻辑的分离,方便后续的维护

    4. 一个方法返回另一个页面(PO)

    PO中定义个方法,如果跳转至另外一个页面,可以直接return至对应跳转的页面,不要在一个方法中写多个页面,不利于后续的维护,有跳转的页面时,直接把跳转的页面定义成一个PO即可,然后在跳转方法中进行rerurn即可

    5. 只为页面中的重要元素创建page类

    通常一个页面的功能是很多的,我们不能为每一个元素创建page类,只为重点关注的功能创建po即可,比如百度首页中,我们为首页、登录及搜索功能创建po即可

    6. 对于不同的结果定义不同的方法

    测试过程中,通常对于一个功能点,有正常的场景,还有异常的场景,在PO中可以定义不同的方法来实现不同结果,比如登录,我们可以定义多个方法进行测试

    def login_success(self):
    	pass
    
    def login_passwd_wrong(self):
    	pass
    
    def login_username_wrong(self):
    	pass
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    二、PageObject的简单使用

    以百度为例,简单记录下pageobject进行自动化脚本设计的过程

    1. 系统功能分析

    实现的功能:

    百度搜索
    百度登录
    百度注册

    涉及的页面:

    百度首页
    搜索页面
    登录页面
    注册页面

    页面的功能:
    首页:搜索跳转、登录跳转
    搜索:搜索功能
    登录:登录功能、注册跳转
    注册:注册功能

    2. PO设计

    根据功能分析中涉及的页面创建po
    首页:index.py、搜索:search.py、登录:login.py、注册:register.py

    根据页面中的功能编写po文件
    首页:index.py

    # 百度首页po
    from selenium.webdriver.common.by import By
    
    from page.login import Login
    from selenium import webdriver
    
    from page.search import Search
    
    
    class Index:
    	
    	# 初始方法
        def __init__(self):
            self._driver = webdriver.Chrome()
            self._driver.get('https://www.baidu.com')
            self._driver.maximize_window()
            self._driver.implicitly_wait(3)
    
    	# 退出方法
        def teardown(self):
            self._driver.quit()
    	
    	# 跳转登录
        def goto_login(self):
            self._driver.find_element(By.ID, 's-top-loginbtn').click()
            return Login(self._driver)
    	
    	# 跳转搜索
        def goto_search(self):
            return Search(self._driver)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    搜索:search.py

    from selenium.webdriver.common.by import By
    from selenium.webdriver.remote.webdriver import WebDriver
    
    
    class Search:
    
        def __init__(self, driver:WebDriver):
            self._driver = driver
    	
    	# 搜索功能封装
        def search(self):
            self._driver.find_element(By.ID, 'kw').send_keys('北京')
            self._driver.find_element(By.ID, 'su').click()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    登录:login.py

    from selenium.webdriver.common.by import By
    from selenium.webdriver.remote.webdriver import WebDriver
    
    from page.register import Register
    
    
    class Login:
        def __init__(self, driver: WebDriver):
            self._driver = driver
    
        # 输入正确的账号和密码
        def login_success(self):
            self._driver.find_element(By.ID, 'TANGRAM__PSP_11__userName').send_keys('test123')
            self._driver.find_element(By.ID, 'TANGRAM__PSP_11__password').send_keys('Aa123456')
            self._driver.find_element(By.ID, 'TANGRAM__PSP_11__submit').click()
    
        # 输入错误的账号和密码
        def login_fail(self):
            self._driver.find_element(By.ID, 'TANGRAM__PSP_11__userName').send_keys('test123')
            self._driver.find_element(By.ID, 'TANGRAM__PSP_11__password').send_keys('Aa123456')
            self._driver.find_element(By.ID, 'TANGRAM__PSP_11__submit').click()
    	
    	# 跳转注册
        def goto_register(self):
            self._driver.find_element(By.ID, 'TANGRAM__PSP_11__regLink').click()
            windows = self._driver.window_handles
            self._driver.switch_to.window(windows[-1])
            return Register(self._driver)
    	# 封装获取错误信息,用于后续断言实用
        def get_error_message(self):
            error_element = self._driver.find_element(By.ID, 'TANGRAM__PSP_11__error')
            error_value = error_element.text
            print(error_value)
            return error_value
         
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    注册:register.py

    from selenium.webdriver.common.by import By
    from selenium.webdriver.remote.webdriver import WebDriver
    
    
    class Register:
    
        def __init__(self, driver: WebDriver):
            self._driver = driver
    	# 注册功能封装
        def register(self):
            self._driver.find_element(By.ID, 'TANGRAM__PSP_4__userName').send_keys('test123')
            self._driver.find_element(By.ID, 'TANGRAM__PSP_4__phone').send_keys('13120991801')
            self._driver.find_element(By.ID, 'TANGRAM__PSP_4__password').send_keys('Aa123456')
            self._driver.find_element(By.ID, 'TANGRAM__PSP_4__verifyCode').send_keys('1234')
            self._driver.find_element(By.ID, 'TANGRAM__PSP_4__isAgree').click()
            self._driver.find_element(By.ID, 'TANGRAM__PSP_4__submit').click()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3. 测试用例设计

    po设计完成后,创建测试类进行测试:test_baidu.py

    from page.index import Index
    
    
    class TestBaidu:
    	# setup中实例化百度首页
        def setup(self):
            self.index = Index()
    	# 登录成功测试
        def test_login_success(self):
            login = self.index.goto_login()
            login.login_success()
            self.index.teardown()
        
        # 登录失败测试
        def test_login_fail(self):
        	login = self.index.goto_login()
            login.login_fail()
            assert "用户名或密码有误,请重新输入或" in login.get_error_message()
            self.index.teardown()
            
    	# 注册测试
        def test_register(self):
            self.index.goto_login().goto_register().register()
            self.index.teardown()
    	# 搜索测试
        def test_search(self):
            self.index.goto_search()
            self.index.teardown()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    总结

    知识点总结:
    1.不用每个po都进行初始化,在__init__方法中传入driver对象即可复用
    2.页面跳转时不要忘了进行窗口的切换操作

  • 相关阅读:
    【算法】【二叉树模块】求二叉树中最大搜索二叉子树,返回头结点
    SQL注入基础---order by \ limit \ 宽字节注入
    【Xcode-宏定义配置】
    Session会话追踪的实现机制
    Dubbo API 笔记——Dubbo协议&最佳实践
    一文掌握Spring MVC REST风格开发
    MySQL数据库进阶第五篇(锁)
    将DataFrame中object类型的列转换为更恰当的数据类型df.infer_objects()
    阿里大于发送短信(用户微服务--消息微服务)
    AnkiPDF Guru软件评测:打开全新学习方式的大门
  • 原文地址:https://blog.csdn.net/weixin_42517691/article/details/125060753