PO设计模式
PO(page object)设计模式是在自动化测试中已经流行起来的一种易于维护和减少代码的设计模式. 在自动化测试中, PO对象作为一个与页面交互的接口. 测试中需要与页面的UI进行交互时, 便调用PO的方法. 这样做的好处是, 如果页面的UI发生了更改,那么测试用例本身不需要更改, 只需更改PO中的代码即可.
PO设计模式具有以下优点:
页面中通常有很多功能点,比如登录、注册、搜索等,在PO中定义方法来代替这些功能,在方法中定义功能的操作逻辑
执行的case中,不要暴露操作的细节,通常是直接调用封装好的po中的方法,比如:
def test_login(self):
self.index.gotologin()
通常细节封装在po定义的方法中,不在测试用例中暴露,这样方便后续的维护,页面有变动时,只需要修改po中方法即可,测试断言相关部分不用修改
在po定义的方法中不要进行断言操作,尽力保持页面逻辑和测试逻辑的分离,方便后续的维护
PO中定义个方法,如果跳转至另外一个页面,可以直接return至对应跳转的页面,不要在一个方法中写多个页面,不利于后续的维护,有跳转的页面时,直接把跳转的页面定义成一个PO即可,然后在跳转方法中进行rerurn即可
通常一个页面的功能是很多的,我们不能为每一个元素创建page类,只为重点关注的功能创建po即可,比如百度首页中,我们为首页、登录及搜索功能创建po即可
测试过程中,通常对于一个功能点,有正常的场景,还有异常的场景,在PO中可以定义不同的方法来实现不同结果,比如登录,我们可以定义多个方法进行测试
def login_success(self):
pass
def login_passwd_wrong(self):
pass
def login_username_wrong(self):
pass
以百度为例,简单记录下pageobject进行自动化脚本设计的过程
实现的功能:
百度搜索
百度登录
百度注册
涉及的页面:
百度首页
搜索页面
登录页面
注册页面
页面的功能:
首页:搜索跳转、登录跳转
搜索:搜索功能
登录:登录功能、注册跳转
注册:注册功能
根据功能分析中涉及的页面创建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)
搜索: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()
登录: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
注册: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()
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.不用每个po都进行初始化,在__init__方法中传入driver对象即可复用
2.页面跳转时不要忘了进行窗口的切换操作