当前位置: 首页 > news >正文

六、UI自动化测试06--PO设计模式

目录

  • 一、PO 设计模式
    • 1. v1 版本
      • 1.1 v1.1
      • 1.2 v1.2
    • 2. v2 版本
    • 3. ⽅法封装套路
    • 4. v3 版本
      • 4.1 浏览器对象管理类的实现
      • 4.2 浏览器对象管理类的优化
      • 4.3 浏览器对象管理类的使⽤
      • 4.4 获取弹窗信息⽅法的封装
    • 5. PO 设计模式
    • 6. v4 版本
      • 6.1 PO⻚⾯元素封装步骤
      • 6.2 测试⽤例的最终代码样式
    • 7. v5 版本
      • 7.1 PO ⽂件对象层代码优化
      • 7.2 PO ⽂件操作层代码优化

一、PO 设计模式

1. v1 版本

说明: 通过测试执⾏框架 pytest, 可以整合所有的同⼀模块的测试⽤例脚本, 并且需要尽⼒符合⼿⼯测试的操作业务逻辑, 最终实现执⾏单个测试脚本, 执⾏同⼀模块的所有测试⽤例

1.1 v1.1

  • 通过测试⽅法整合测试脚本
"""
整合多个脚本⾄同⼀个测试⽤例中
"""
import pytest
from time import sleep
from selenium import webdriverclass TestLogin(object):"""登录测试类"""def test_account_does_not_exist(self):"""账号不存在测试⽅法"""driver = webdriver.Chrome()driver.get('http://127.0.0.1/')driver.maximize_window() # 窗⼝最⼤化driver.implicitly_wait(10) # 隐式等待# 1. 点击⾸⻚的‘登录’链接,进⼊登录⻚⾯driver.find_element_by_link_text('登录').click()# 2. 输⼊⼀个不存在的⽤户名driver.find_element_by_id('username').send_keys('13811110001')# 3. 输⼊密码driver.find_element_by_id('password').send_keys('123456')# 4. 输⼊验证码driver.find_element_by_id('verify_code').send_keys('8888')# 5. 点击登录按钮driver.find_element_by_name('sbtbutton').click()# 6. 获取错误提示信息# 获取元素⽂本值: 元素对象.textmsg = driver.find_element_by_class_name('layui-layercontent').textprint('错误信息为:', msg)sleep(3)driver.quit()def test_wrong_password(self):"""密码错误测试⽅法"""driver = webdriver.Chrome()driver.get('http://127.0.0.1/')driver.maximize_window() # 窗⼝最⼤化driver.implicitly_wait(10) # 隐式等待# 1. 点击⾸⻚的‘登录’链接,进⼊登录⻚⾯driver.find_element_by_link_text('登录').click()# 2. 输⼊⽤户名driver.find_element_by_id('username').send_keys('13800001111')# 3. 输⼊错误密码driver.find_element_by_id('password').send_keys('error')# 4. 输⼊验证码driver.find_element_by_id('verify_code').send_keys('8888')# 5. 点击登录按钮driver.find_element_by_name('sbtbutton').click()# 6. 获取错误提示信息# 获取元素⽂本值: 元素对象.textmsg = driver.find_element_by_class_name('layui-layer-content').textprint('错误信息为:', msg)sleep(3)driver.quit()if __name__ == '__main__':pytest.main(['-s', 'tpshop_login_1.py'])

1.2 v1.2

  • 通过 setup() 和 teardown() ⽅法优化多个脚本相同的前置后后置操作
"""
整合多个脚本⾄同⼀个测试⽤例中
"""
import pytest
from time import sleep
from selenium import webdriverclass TestLogin(object):"""登录测试类"""def setup(self):self.driver = webdriver.Chrome()self.driver.get('http://127.0.0.1/')self.driver.maximize_window() # 窗⼝最⼤化self.driver.implicitly_wait(10) # 隐式等待def teardown(self):sleep(3)self.driver.quit()def test_account_does_not_exist(self):"""账号不存在测试⽅法"""# driver = webdriver.Chrome()# driver.get('http://127.0.0.1/')# driver.maximize_window() # 窗⼝最⼤化# driver.implicitly_wait(10) # 隐式等待# 1. 点击⾸⻚的‘登录’链接,进⼊登录⻚⾯self.driver.find_element_by_link_text('登录').click()# 2. 输⼊⼀个不存在的⽤户名self.driver.find_element_by_id('username').send_keys('13811110001')# 3. 输⼊密码self.driver.find_element_by_id('password').send_keys('123456')# 4. 输⼊验证码self.driver.find_element_by_id('verify_code').send_keys('8888')# 5. 点击登录按钮self.driver.find_element_by_name('sbtbutton').click()# 6. 获取错误提示信息# 获取元素⽂本值: 元素对象.textsleep(2)msg = self.driver.find_element_by_class_name('layui-layer-content').textprint('错误信息为:', msg)# sleep(3)# driver.quit()def test_wrong_password(self):"""密码错误测试⽅法"""# driver = webdriver.Chrome()# driver.get('http://127.0.0.1/')# driver.maximize_window() # 窗⼝最⼤化# driver.implicitly_wait(10) # 隐式等待# 1. 点击⾸⻚的‘登录’链接,进⼊登录⻚⾯self.driver.find_element_by_link_text('登录').click()# 2. 输⼊⽤户名self.driver.find_element_by_id('username').send_keys('138000011
11')# 3. 输⼊错误密码self.driver.find_element_by_id('password').send_keys('error')# 4. 输⼊验证码self.driver.find_element_by_id('verify_code').send_keys('8888')# 5. 点击登录按钮self.driver.find_element_by_name('sbtbutton').click()# 6. 获取错误提示信息# 获取元素⽂本值: 元素对象.textsleep(2)msg = self.driver.find_element_by_class_name('layuilayer-content').textprint('错误信息为:', msg)# sleep(3)# driver.quit()if __name__ == '__main__':pytest.main(['-s', 'tpshop_login_2.py'])

2. v2 版本

  • 通过 setup_class() 和 teardown_class() ⽅法使脚本的执⾏逻辑跟符合⼿⼯测试逻辑
"""
整合多个脚本⾄同⼀个测试⽤例中
"""
import pytest
from time import sleep
from selenium import webdriverclass TestLogin(object):"""登录测试类"""def setup_class(self):self.driver = webdriver.Chrome()self.driver.get('http://127.0.0.1/')self.driver.maximize_window() # 窗⼝最⼤化self.driver.implicitly_wait(10) # 隐式等待def teardown_class(self):sleep(3)self.driver.quit()def setup(self):# self.driver = webdriver.Chrome()# self.driver.get('http://127.0.0.1/')# self.driver.maximize_window() # 窗⼝最⼤化# self.driver.implicitly_wait(10) # 隐式等待# 打开⾸⻚self.driver.get('http://127.0.0.1/')# 点击登录self.driver.find_element_by_link_text('登录').click()def teardown(self):# sleep(3)# self.driver.quit()passdef test_account_does_not_exist(self):"""账号不存在测试⽅法"""# 1. 点击⾸⻚的‘登录’链接,进⼊登录⻚⾯# self.driver.find_element_by_link_text('登录').click()# 2. 输⼊⼀个不存在的⽤户名self.driver.find_element_by_id('username').send_keys('13811110001')# 3. 输⼊密码self.driver.find_element_by_id('password').send_keys('123456')# 4. 输⼊验证码self.driver.find_element_by_id('verify_code').send_keys('8888')# 5. 点击登录按钮self.driver.find_element_by_name('sbtbutton').click()# 6. 获取错误提示信息# 获取元素⽂本值: 元素对象.textsleep(2)msg = self.driver.find_element_by_class_name('layui-layer-content').textprint('错误信息为:', msg)def test_wrong_password(self):"""密码错误测试⽅法"""# 1. 点击⾸⻚的‘登录’链接,进⼊登录⻚⾯# self.driver.find_element_by_link_text('登录').click()# 2. 输⼊⽤户名self.driver.find_element_by_id('username').send_keys('13800001111')# 3. 输⼊错误密码self.driver.find_element_by_id('password').send_keys('error')# 4. 输⼊验证码self.driver.find_element_by_id('verify_code').send_keys('8888')# 5. 点击登录按钮self.driver.find_element_by_name('sbtbutton').click()# 6. 获取错误提示信息# 获取元素⽂本值: 元素对象.textsleep(2)msg = self.driver.find_element_by_class_name('layui-layer-content').textprint('错误信息为:', msg)if __name__ == '__main__':pytest.main(['-s', 'tpshop_login_3.py'])

3. ⽅法封装套路

    1. 确定⽅法的存放位置: 找位置
    1. 给⽅法起个合适名字: 起名字
    1. 放⼊要封装的代码内容: 放代码
    1. 确认是否需要参数和返回值: 确必要
    1. 调⽤封装好的⽅法使⽤: 做调⽤

4. v3 版本

4.1 浏览器对象管理类的实现

"""
公共⽅法模块: 习惯命名 utils
"""
from selenium import webdriver
from time import sleepclass DriverUtil(object):"""浏览器对象管理类"""driver = None # 浏览器对象变量初始化状态def get_driver(self):"""获取浏览器对象⽅法"""# 说明: 为了防⽌在同⼀次测试过程中, 调⽤获取浏览器对象⽅法时,# 都会创建⼀个新的浏览器对象, 因此有必要先判断对象是否存在, 
不存在时在创建!if self.driver is None:self.driver = webdriver.Chrome()self.driver.get('http://127.0.0.1/')self.driver.maximize_window() # 窗⼝最⼤化self.driver.implicitly_wait(10) # 隐式等待return self.driverdef quit_driver(self):"""退出浏览器对象⽅法"""# 说明: 必须保证浏览器对象存在, 才能执⾏退出操作if self.driver: # 等价于: if self.driver is not None:sleep(3)self.driver.quit()self.driver = None # 保险⼿段: 移除对象后, 保留对象变量, 以备下⼀次使⽤if __name__ == '__main__':my_driver = DriverUtil()my_driver.get_driver()sleep(2)my_driver.quit_driver()

4.2 浏览器对象管理类的优化

"""
公共⽅法模块: 习惯命名 utils
"""
from selenium import webdriver
from time import sleepclass DriverUtil(object):"""浏览器对象管理类"""# 说明: 对象变量只需要在类定义内部使⽤, 因此定义为私有__driver = None # 浏览器对象变量初始化状态@classmethoddef get_driver(cls):"""获取浏览器对象⽅法"""# 说明: 为了防⽌在同⼀次测试过程中, 调⽤获取浏览器对象⽅法时,# 都会创建⼀个新的浏览器对象, 因此有必要先判断对象是否存在, 不存在时在创建!if cls.__driver is None:cls.__driver = webdriver.Chrome()cls.__driver.get('http://127.0.0.1/')cls.__driver.maximize_window() # 窗⼝最⼤化cls.__driver.implicitly_wait(10) # 隐式等待return cls.__driver@classmethoddef quit_driver(cls):"""退出浏览器对象⽅法"""# 说明: 必须保证浏览器对象存在, 才能执⾏退出操作if cls.__driver: # 等价于: if self.driver is not None:sleep(3)cls.__driver.quit()cls.__driver = None # 保险⼿段: 移除对象后, 保留对象变量, 以备下⼀次使⽤if __name__ == '__main__':# my_driver = DriverUtil()# my_driver.get_driver()# sleep(2)# my_driver.quit_driver()# 说明: 定义为类⽅法, 可以直接由类对象调⽤, 省略实例化对象步骤DriverUtil.get_driver() # 获取浏览器对象sleep(2)DriverUtil.quit_driver() # 退出浏览器对象

4.3 浏览器对象管理类的使⽤

"""
整合多个脚本⾄同⼀个测试⽤例中
"""
import pytest
from time import sleep
from selenium import webdriverfrom utils import DriverUtilclass TestLogin(object):"""登录测试类"""def setup_class(self):# self.driver = webdriver.Chrome()# self.driver.get('http://127.0.0.1/')# self.driver.maximize_window() # 窗⼝最⼤化# self.driver.implicitly_wait(10) # 隐式等待self.driver = DriverUtil.get_driver() # 获取浏览器对象def teardown_class(self):# sleep(3)# self.driver.quit()DriverUtil.quit_driver() # 退出浏览器对象def setup(self):# 打开⾸⻚self.driver.get('http://127.0.0.1/')# 点击登录self.driver.find_element_by_link_text('登录').click()def teardown(self):passdef test_account_does_not_exist(self):"""账号不存在测试⽅法"""# 2. 输⼊⼀个不存在的⽤户名self.driver.find_element_by_id('username').send_keys('13811110001')# 3. 输⼊密码self.driver.find_element_by_id('password').send_keys('123456')# 4. 输⼊验证码self.driver.find_element_by_id('verify_code').send_keys('8888')# 5. 点击登录按钮self.driver.find_element_by_name('sbtbutton').click()# 6. 获取错误提示信息# 获取元素⽂本值: 元素对象.textsleep(2)msg = self.driver.find_element_by_class_name('layui-layer-content').textprint('错误信息为:', msg)def test_wrong_password(self):"""密码错误测试⽅法"""# 2. 输⼊⽤户名self.driver.find_element_by_id('username').send_keys('13800001111')# 3. 输⼊错误密码self.driver.find_element_by_id('password').send_keys('error')# 4. 输⼊验证码self.driver.find_element_by_id('verify_code').send_keys('8888')# 5. 点击登录按钮self.driver.find_element_by_name('sbtbutton').click()# 6. 获取错误提示信息# 获取元素⽂本值: 元素对象.textsleep(2)msg = self.driver.find_element_by_class_name('layui-layer-content').textprint('错误信息为:', msg)if __name__ == '__main__':pytest.main(['-s', 'tpshop_login_3.py'])

4.4 获取弹窗信息⽅法的封装

from selenium import webdriver
from time import sleepdef get_alert_msg():"""获取弹窗信息⽅法"""sleep(2)# msg = self.driver.find_element_by_class_name('layui-layercontent').text# msg = driver.find_element_by_class_name('layui-layercontent').textmsg = 
DriverUtil.get_driver().find_element_by_class_name('layui-layer-content').textreturn msgclass DriverUtil(object):"""浏览器对象管理类"""__driver = None # 浏览器对象变量初始化状态@classmethoddef get_driver(cls):"""获取浏览器对象⽅法"""if cls.__driver is None:cls.__driver = webdriver.Chrome() # 浏览器类型cls.__driver.get('http://127.0.0.1/') # 项⽬地址cls.__driver.maximize_window() # 窗⼝最⼤化cls.__driver.implicitly_wait(10) # 隐式等待return cls.__driver@classmethoddef quit_driver(cls):"""退出浏览器对象⽅法"""if cls.__driver:sleep(3)cls.__driver.quit()cls.__driver = Noneif __name__ == '__main__':DriverUtil.get_driver() # 获取浏览器对象sleep(2)DriverUtil.quit_driver() # 退出浏览器对象

5. PO 设计模式

  • 说明: PO 模式⼜可以叫 POM(P:Page O:Object), 是 UI ⾃动化测试中⼀个⾮常流⾏的设计模式(代码套路)

  • 核⼼: 将元素定位及操作和业务逻辑, 拆分三个层⾯(每个层⾯对应⼀个单独的类), 然后通过调⽤完成最终的测试执⾏⾏为的过程

  • 三个层⾯: 对象库层/操作层/业务层

在这里插入图片描述

6. v4 版本

6.1 PO⻚⾯元素封装步骤

    1. 对应⻚⾯创建⻚⾯ PO 代码⽂件, 命名规则: ⻚⾯功能_page.py, 例如⾸⻚: index_page.py
    1. 定义三个类: 对象层(XxxPage)/操作层(XxxHandle)/业务层(XxxTask)
    1. 对象层:
    • 1> init ⽅法中获取浏览器对象
    • 2> ⾃定义⽅法: 封装元素定位⽅法
    • 3> 封装元素定位⽅法需要添加返回值!
    1. 操作层:
    • 1> init ⽅法获取对象层对象, 根据类名写对象变量名
    • 2> ⾃定义⽅法: 封装元素操作⽅法
    1. 业务层:
    • 1> init ⽅法获取操作层对象, 根据类名写对象变量名
    • 2> ⾃定义⽅法: 封装测试业务逻辑
    1. 在测试⽤例⽂件中, 实例化业务层对象, 调⽤测试业务⽅法, 执⾏测试

代码示例: ⾸⻚⻚⾯

"""
⾸⻚⻚⾯
"""
from utils import DriverUtilclass IndexPage(object):"""⾸⻚对象层"""def __init__(self):self.driver = DriverUtil.get_driver() # 获取浏览器对象def find_login(self):"""定位登录⽅法"""# self.driver.find_element_by_link_text('登录')# self.driver = DriverUtil.get_driver() # 获取浏览器对象return self.driver.find_element_by_link_text('登录')class IndexHandle(object):"""⾸⻚操作层"""def __init__(self):self.index_page = IndexPage() # 获取对象层对象def click_login(self):"""点击登录⽅法"""# element = IndexPage()# element.find_login().click()self.index_page.find_login().click()class IndexTask(object):"""⾸⻚业务层"""def __init__(self):self.index_handle = IndexHandle() # 获取操作层对象def go_to_login(self):"""跳转登录⻚⾯⽅法"""self.index_handle.click_login()

代码示例: 登录⻚⾯

"""
登录⻚⾯
"""
from utils import DriverUtilclass LoginPage(object):"""登录对象层"""def __init__(self):self.driver = DriverUtil.get_driver() # 获取浏览器对象def find_username(self):"""定位⽤户名⽅法"""return self.driver.find_element_by_id('username')def find_password(self):"""定位密码⽅法"""return self.driver.find_element_by_id('password')def find_verify_code(self):"""定位验证码⽅法"""return self.driver.find_element_by_id('verify_code')def find_login_btn(self):"""定位登录按钮⽅法"""return self.driver.find_element_by_name('sbtbutton')class LoginHandle(object):"""登录操作层"""def __init__(self):self.login_page = LoginPage() # 获取对象层对象def input_username(self, name):"""输⼊⽤户名⽅法"""self.login_page.find_username().send_keys(name)def input_password(self, pwd):"""输⼊密码⽅法"""self.login_page.find_password().send_keys(pwd)def input_verify_code(self, code):"""输⼊验证码⽅法"""self.login_page.find_verify_code().send_keys(code)def click_login_btn(self):"""点击登录按钮⽅法"""self.login_page.find_login_btn().click()class LoginTask(object):"""登录业务层"""def __init__(self):self.login_handle = LoginHandle() # 获取操作层对象def login_method(self, name, pwd, code):"""登录⽅法"""self.login_handle.input_username(name) # 输⼊⽤户名self.login_handle.input_password(pwd) # 输⼊密码self.login_handle.input_verify_code(code) # 输⼊验证码self.login_handle.click_login_btn() # 点击登录按钮

6.2 测试⽤例的最终代码样式

"""
整合多个脚本⾄同⼀个测试⽤例中
"""
import pytest
from utils import DriverUtil, get_alert_msg
from v4.index_page import IndexTask
from v4.login_page import LoginTaskclass TestLogin(object):"""登录测试类"""def setup_class(self):self.driver = DriverUtil.get_driver() # 获取浏览器对象self.index_task = IndexTask() # 实例化⾸⻚业务层对象self.login_task = LoginTask() # 实例化登录⻚⾯业务层对象def teardown_class(self):DriverUtil.quit_driver() # 退出浏览器对象def setup(self):# 打开⾸⻚self.driver.get('http://127.0.0.1/')# 点击登录# self.driver.find_element_by_link_text('登录').click()self.index_task.go_to_login() # 跳转登录def teardown(self):passdef test_account_does_not_exist(self):"""账号不存在测试⽅法"""# # 2. 输⼊⼀个不存在的⽤户名# 
self.driver.find_element_by_id('username').send_keys('13811110001')# # 3. 输⼊密码# 
self.driver.find_element_by_id('password').send_keys('123456')# # 4. 输⼊验证码# 
self.driver.find_element_by_id('verify_code').send_keys('8888')# # 5. 点击登录按钮# self.driver.find_element_by_name('sbtbutton').click()self.login_task.login_method('13811110001', '123456', '8888')# 6. 获取错误提示信息msg = get_alert_msg() # 获取弹窗信息print('错误信息为:', msg)def test_wrong_password(self):"""密码错误测试⽅法"""# # 2. 输⼊⽤户名# 
self.driver.find_element_by_id('username').send_keys('13800001111')# # 3. 输⼊错误密码#self.driver.find_element_by_id('password').send_keys('error')# # 4. 输⼊验证码# 
self.driver.find_element_by_id('verify_code').send_keys('8888')# # 5. 点击登录按钮# self.driver.find_element_by_name('sbtbutton').click()self.login_task.login_method('13800001111', 'error', '8888')# 6. 获取错误提示信息msg = get_alert_msg() # 获取弹窗信息print('错误信息为:', msg)if __name__ == '__main__':pytest.main(['-s', 'tpshop_login.py'])

7. v5 版本

7.1 PO ⽂件对象层代码优化

class LoginPage(object):"""登录对象层"""def __init__(self):self.driver = DriverUtil.get_driver() # 获取浏览器对象# 说明: 将元素的定位⽅法及特征值封装成属性, 能够实现集中管理⽬标元素的定位⽅法及特征值self.name = (By.ID, 'username') # ⽤户名self.pwd = (By.ID, 'password') # 密码self.code = (By.ID, 'verify_code') # 验证码self.btn = (By.NAME, 'sbtbutton') # 登录按钮def find_username(self):"""定位⽤户名⽅法"""# return self.driver.find_element_by_id('username')# return self.driver.find_element(By.ID, 'username')return self.driver.find_element(self.name[0], self.name[1])def find_password(self):"""定位密码⽅法"""# return self.driver.find_element_by_id('password')return self.driver.find_element(self.pwd[0], self.pwd[1])def find_verify_code(self):"""定位验证码⽅法"""# return self.driver.find_element_by_id('verify_code')return self.driver.find_element(self.code[0], self.code[1])def find_login_btn(self):"""定位登录按钮⽅法"""# return self.driver.find_element_by_name('sbtbutton')return self.driver.find_element(self.btn[0], self.btn[1])

7.2 PO ⽂件操作层代码优化

class LoginHandle(object):"""登录操作层"""def __init__(self):self.login_page = LoginPage() # 获取对象层对象def input_username(self, name):"""输⼊⽤户名⽅法"""# 说明: 在执⾏输⼊操作前, 应该先执⾏清空操作self.login_page.find_username().clear()self.login_page.find_username().send_keys(name)def input_password(self, pwd):"""输⼊密码⽅法"""self.login_page.find_password().clear()self.login_page.find_password().send_keys(pwd)def input_verify_code(self, code):"""输⼊验证码⽅法"""self.login_page.find_verify_code().clear()self.login_page.find_verify_code().send_keys(code)def click_login_btn(self):"""点击登录按钮⽅法"""self.login_page.find_login_btn().click()
http://www.xdnf.cn/news/229321.html

相关文章:

  • QT—布局管理器之QStackedLayout篇
  • UE5 项目迁移 注意事项记录
  • 永磁同步电机控制算法--线性ADRC转速环控制器(一阶、二阶)
  • canvas动画:点随机运动 距离内自动连接成线 鼠标移动自动吸附附近的点
  • Q2(流动式)起重机司机理论考试精选题及答案
  • 2025年5月计划(Ue4.0shader源码抄写+ue独立游戏每天一小节)
  • 《多端统一的终极答案:X5内核增强版的渲染优化全解析》
  • 微调 LLaMA 2:定制大型语言模型的分步指南
  • Linux 部署以paddle Serving 的方式部署 PaddleOCR CPU版本
  • 虚拟机对前端开发的实用价值:提升效率与解决痛点的完整指南
  • Nanote:极简Markdown笔记应用
  • React Native 从零开始完整教程(环境配置 → 国内镜像加速 → 运行项目)
  • LeetCode 1295.统计位数为偶数的数字:模拟
  • Arduino IDE中更新esp32 3.2.0版本的办法
  • 开源协议全解析:类型、选择与法律风险规避指南
  • Sigmoid函数简介及其Python实现
  • uv安装及使用
  • 在pycharm中创建Django项目并启动
  • TIME_WAIT状态+UDP概念及模拟实现服务器和客户端收发数据
  • 决策树在电信客户流失分析中的实战应用
  • 126. 单词接龙 II
  • 数学建模论文手的学习日常01
  • 牛客:AB5 点击消除
  • 【已解决】TensorRT安装好后加载不了或者转换不了engine模型,或者加载时报错
  • LeetCode392_判断子序列
  • 基于PHP的在线编程课程学习系统
  • [特殊字符] 开发工作高内存占用场景下,Windows 内存压缩机制是否应该启用?实测分析与优化建议
  • 涨薪技术|0到1学会性能测试第44课-apachetop模块监控
  • MCU片上存储器的类型与特性
  • 【学习 python day5】