Page Object模式
以页面为单位组织封装, 隐藏实现细节; 可读性提高, 减少findElement,click代码, 页面发生变化修改对应page,不影响整体用例
原则:
- 公共方法代表UI功能
- 同样的行为不同结果可设计为不同的方法
- 方法返回Page Object或者用于断言的数据
- 不在方法内加断言
- 不要暴露UI元素给外部
- 不需要建模所有UI元素
解读:
- 以页面为单位组织封装, 页面发生变化修改对应page,不影响整体用例。
- UI元素定位及交互细节封装在方法内, 用公共方法代表UI功能,提高了可读性,方便快速了解用例的逻辑
- 公共方法返回Page Object或者用于断言的数据,不在方法内加断言。在用例模块调用page公共方法完成业务流程并断言。这样元素定位交互细节被隐藏,用例层只关注po对象方法和断言逻辑,更加易于维护。
改造:
用例组织结构
-
使用package管理模块,基本可以分成5个模块
- page: 完成对各个页面封装
- driver:完成对web、Android、iOS驱动的封装
- case:调用各个page完成业务流程并进行断言
- data:配置文件和数据驱动(测试数据,测试步骤,断言)
- utils: 其他便捷的功能封装
-
使用class管理业务对象
-
使用method实现具体行为
测试用例使用简单几行代码根据方法名快速识别功能
App类封装启动和退出的细节
class App:
driver:WebDriver = None
platform = None
ANDROID = 1
IOS = 2
@classmethod
def start(cls):
caps = {}
caps["appActivity"] = ".HomeActivity"
caps["platformName"] = "Android"
caps["deviceName"] = "JTK5T19917028084"
caps["appPackage"] = "com.mintegral.sdk.demo"
cls.driver = webdriver.Remote("http://localhost:4723/wd/hub", caps)
cls.platform = cls.ANDROID
return FrontPage(cls.driver)
@classmethod
def quit(cls):
cls.driver.quit()
@classmethod
def getPlatform(cls):
return cls.platform
start后返回FrontPage对象。
frontpage完成对该页面下一步操作的实现,继承自BasePage,返回下一个页面po
class FrontPage(BasePage):
native_indicator = (By.XPATH,"//*[@text='Native']")
def toNative(self):
self.findElement_then_click(self.native_indicator)
return NativeChoicePage(self.driver)
封装过程(类似于TDD风格):
- 先根据各页面封装Page类和方法,方法可以先为空实现
- 编写用例,不断重构page里的方法的入参和返回值
- 开始实现page里的方法
- 调试
BasePage封装
class BasePage:
def __init__(self,driver:WebDriver):
self.driver = driver
def findElement(self,indicator):
return self.driver.find_element(*indicator)
def findElement_then_click(self,indicator):
self.findElement(indicator).click()
......
- 实现通用的page方法,对常用行为进行封装
- 管理各种driver
- 减少每个page对appium/selenium各种库的依赖
- 可以加入异常弹框处理(广告,tips,升级,评价)