传统的设计中,在新增测试用例之后,测试代码会有如下几个问题:
(1)易读性差:一连串的find_element和wait.until会使代码显得杂乱无章,不方便阅读;
(2)可扩展性不好:用例孤立,无法扩展;
(3)可复用性差:无公共方法,很难进行复用;
(4)可维护性差:一旦页面元素发生变化,需要维护修改大量的测试用例。
所以,我们有必要掌握PO设计模式,以弥补传统设计的不足。
PO(Page Object)设计模式是selenium自动化测试中最佳的设计模式之一,主要体现在对界面交互细节的封装,我们在实际测试中只需关注业务流程就可以了。
PO设计模式是一种自动化测试设计模式:将测试对象和测试用例进行分离,此时测试对象只需负责页面元素的定位和对元素进行相应的操作,因此我们可以将测试对象,即页面封装成一个类,其中,
类的属性:页面元素的定位
类的方法:对页面元素的操作
通过上述的描述,我们可以简单的将PO理解为:
(1)PO对象是一种设计模式,用来管理和维护一组web元素的对象库;
(2)在PO设计模式下,应用程序的每一个页面都有一个对应的page类;
(3)每一个page类只需负责维护该web页面的元素和操作这些元素的方法;
(4)每一个page中方法的名称最好根据相应的业务场景进行命名,做到见名识意。例如通常我们登陆成功后,在进行下一个业务操作时,通常需要等待几秒钟,此时我们可以使用这样的命名方法:waitint_for_login_success()或者waitingForLoginSuccess();
(5)测试用例=调用页面类的方法+测试数据 -- 本节中暂时还未将测试数据和测试用例进行分离,只涉及设计测试用例和测试对象的分离;
(6)测试用例中可能会涉及多个测试对应,如 1个用例 = 页面A + 页面B + 页面C + 页面D等。
下面我们将通过具体的实例,进一步理解PO设计模式。
场景描述:使用用户名和密码登录课堂派,要求使用PO设计模式。
操作流程:
(1)先梳理业务,根据业务需求使用excel编写测试用例;
(2)明确测试用例中需要使用的页面和测试数据以及断言; -- 此时需要熟悉测试用例中每一步的操作流程,代码可以先不用实现
(3)实现具体的页面对象和页面元素定位;
(4)准备测试数据 -- 使用python代码来存放测试数据;
(5)页面对象和测试数据准备就绪后,对测试用例进行填充。
代码实现:
(1)代码组织结构:
(2)各部分实现
conftest.py
- 前置:实例化dirver,并且访问课堂派登录页面,返回driver对象
- 后置:关闭浏览器
1 import pytest 2 from selenium import webdriver 3 4 @pytest.fixture 5 def init(): 6 # 实例化driver,访问登录页面 7 driver = webdriver.Chrome() 8 driver.get("https://www.ketangpai.com/#/login") 9 yield driver 10 driver.quit()
pageObjects.login_page.py:登录页面元素定位和操作
1 from selenium.webdriver.remote.webdriver import WebDriver # 引入webDriver的父类 2 from selenium.webdriver.common.by import By 3 from selenium.webdriver.support import expected_conditions as EC 4 from selenium.webdriver.support.wait import WebDriverWait 5 6 class LoginPage: 7 8 # 对待操作的元素进行定位:类属性 9 user_loc = (By.XPATH, '//input[@placeholder="请输入邮箱/手机号/账号"]') 10 pwd_loc = (By.XPATH, '//input[@placeholder="请输入密码"]') 11 btn_loc = (By.XPATH, '//button[contains(@class,"primary")]') 12 13 def __init__(self,driver:WebDriver): # driver:WebDriver明确传入参数的属性 14 self.driver = driver 15 self.wait = WebDriverWait(self.driver,20) 16 pass 17 18 # 登录相关操作 19 def login(self,user,password): 20 self.wait.until(EC.visibility_of_element_located(self.btn_loc)) 21 self.driver.find_element(*self.user_loc).send_keys(user) 22 self.driver.find_element(*self.pwd_loc).send_keys(password) 23 ele = self.driver.find_element(*self.btn_loc) 24 js_code = "arguments[0].click()" 25 self.driver.execute_script(js_code, ele) # 使用js执行页面的点击操作
pageObjects.home_page.py:主页面元素定位和操作
1 from selenium.webdriver.remote.webdriver import WebDriver # 引入webDriver的父类 2 from selenium.webdriver.common.by import By 3 from selenium.webdriver.support import expected_conditions as EC 4 from selenium.webdriver.support.wait import WebDriverWait 5 6 class HomePage: 7 8 assign_loc = (By.XPATH,'//span[@title="任务管理"]') 9 10 def __init__(self,driver:WebDriver): 11 self.driver = driver 12 self.wait = WebDriverWait(self.driver,6) 13 pass 14 15 # 判断任务元素是否存在 16 def is_assign_exist(self): 17 # 判断元素是否可见 18 try: 19 self.wait.until(EC.visibility_of_element_located(self.assign_loc)) 20 except: 21 return False 22 else: 23 return True
testCases.test_login.py
1 import pytest 2 from pageObjects.login_page import LoginPage 3 from pageObjects.home_page import HomePage 4 5 @pytest.mark.usefixtures 6 class TestLogin: 7 8 def test_login(self,init): # int为前置返回的driver对象,在实例化页面对象时,需要使用driver对象 9 LoginPage(init).login("1522317xxxx","jyfxxxxxx") 10 # 断言 11 assert HomePage(init).is_assign_exist()
小结:
在本节中,我们了解了selenium自动化测试中的PO设计模式,并通过具体的案例实现了测试对象和测试用例的分离。