一、简介
主要特点体现在“对界面交互细节的封装”上,使测试用例更专注于业务的操作,从而提高测试用例的可维护性。解决UI变动问题。
page对象的一个基本原则经验法则是:凡是人能做的事,page对象通过软件客户端都能做到。因此,它应该提供一个易于编程的接口,并隐藏窗口中底层的部件。当访问一个文本框时,应该通过一个访问方法(Access Method)实现字符串的获取与返回,复选框应当使用布尔值,按钮应当被表示为行为导向的方法名。page对象应当把在GUI控件上所有查询和操作数据的行为封装为方法。即使改变具体的元素,page对象的接口也不应当发生变化。通过给页面建模,使其对应用程序的使用者变得有意义。
Page Object设计模式应遵循的原则:
- 应该易于使用
- 有清晰的结构,如PageObjects对应页面对象,PageModules对应页面内容
- 只写测试内容,不写基础内容
- 在可能的情况下防止样板代码
- 不需要自己管理浏览器
- 在运行时选择浏览器,而不是类级别
- 不需要直接接触selenium
Page Object的设计思想是:把元素定位与元素操作进行分层,结果是当元素发生变化时,只需要维护page层的元素定位,而不需要关心在哪些测试用例中使用了这些元素。在编写测试用例时,也不需要关心元素是如何定位的。
二、简单实现
1.测试代码
1 def test_baidu_search_case1(self): 2 self.driver.get(self.base_url) 3 self.driver.find_element_by_id("kw").send_keys("selenium") 4 self.driver.find_element_by_id("su").click() 5 6 def test_baidu_search_case2(self): 7 self.driver.get(self.base_url) 8 self.driver.find_element_by_id("kw").send_keys("unittest") 9 self.driver.find_element_by_id("su").click() 10 11 def test_baidu_search_case3(self): 12 self.driver.get(self.base_url) 13 self.driver.find_element_by_id("kw").send_keys("page object") 14 self.driver.find_element_by_id("su").click()
这种每次都要定位元素,再对这些元素操作的重复性行为,会带来这样一个问题:就是一旦元素定位发生改变,每条测试用例都要将定位元素的代码加以修改,若是自动化测试项目中存在上百条测试用例,就会提高自动化测试用例的维护成本。
Page Object的设计思想上是把元素定位与元素操作进行分层,当元素发生变化时,只需要维护page层的元素定位,而不需要关心在哪些测试用例当中使用了这些元素。在编写测试用例时,也不必关心元素是如何定位的。
创建baidu_page.py文件
1 class BaiduPage(): 2 3 def __init__(self, driver): 4 self.driver = driver 5 6 def search_input(self, search_key): 7 self.driver.find_element_by_id("kw").send_keys(search_key) 8 9 def search_button(self): 10 self.driver.find_element_by_id("su").click()
创建BaiduPage类,分别封装输入搜索内容和点击确定搜索按钮的search_input()和search_button()方法,这里的封装只针对一个页面中可能会操作到的元素,原则是一个元素封装成一个方法。当元素的定位方法发生改变时,只需要维护这里的方法即可,而不必关心这个方法被哪个测试用例使用了。
1 from files.PO.baidu_page import BaiduPage 2 3 4 def test_baidu_search_case1(self): 5 self.driver.get(self.base_url) 6 bd = BaiduPage(self.driver) 7 bd.search_input("selenium") 8 bd.search_button() 9 10 11 def test_baidu_search_case2(self): 12 self.driver.get(self.base_url) 13 bd = BaiduPage(self.driver) 14 bd.search_input("unittest") 15 bd.search_button() 16 17 18 def test_baidu_search_case3(self): 19 self.driver.get(self.base_url) 20 bd = BaiduPage(self.driver) 21 bd.search_input("page object") 22 bd.search_button(
首先在测试中导入BaiduPage类,然后在每个测试用例中为BaiduPage类传入驱动,以便轻松地使用它封装的方法来设计具体的测试用例了。
2.改进Page Object封装
创建base.py文件,内容如下:
1 class BasePage: 2 """ 3 基础Page层,封装一些常用的方法 4 """ 5 6 def __init__(self, driver): 7 self.driver = driver 8 9 # 打开页面 10 def open(self, url=None): 11 if url is None: 12 self.driver.get(self.url) 13 else: 14 self.driver.get(url) 15 16 # id定位 17 def by_id(self, id_): 18 return self.driver.find_element_by_id(id_) 19 20 # name定位 21 def by_name(self, name_): 22 return self.driver.find_element_by_name(name_) 23 24 # class定位 25 def by_class(self, class_name): 26 return self.driver.find_element_by_class(class_name) 27 28 # Xpath定位 29 def by_xpath(self, xpath): 30 return self.driver.find_element_by_xpath(xpath) 31 32 # CSS定位 33 def by_css(self, css): 34 return self.driver.find_element_by_css_selector(css) 35 36 # 获取title 37 def get_title(self): 38 return self.driver.title 39 40 # 获取页面text,仅使用XPath定位 41 def get_text(self, xpath): 42 return self.by_xpath(xpath).text 43 44 # 执行JavaScript脚本 45 def js(self, script): 46 self.driver.execute_script(script)
创建BasePage类作为所有Page类的基类,在BasePage类中封装一些方法
- open()方法用于打开网页,它接收一个url参数,默认为None。如果url参数为None,则默认打开子类中定义的url
- by_id()和by_name()方法。由于Selenium提供的元素定位方法很长,这里做了简化,为的是在子类中使用更加简便
- get_title()和get_text()方法。需要注意的是,get_text()方法需要接收元素定位,这里默认为xpath定位。
修改后的baidu_page.py文件
1 from files.PO.base import BasePage 2 3 4 class BaiduPage(BasePage): 5 """百度Page层,百度页面封装操作到的元素""" 6 url = "http://www.baidu.com" 7 8 def search_input(self, search_key): 9 self.by_id("kw").send_keys(search_key) 10 11 def search_button(self): 12 self.by_id("su").click()
创建BaiduPage.py类继承BasePage类,定义url变量,供父类中的open()方法使用。在测试用例中,使用BaiduPage类及它所继承的父类中的方法
1 from selenium import webdriver 2 import unittest 3 from time import sleep 4 from files.PO.baidu_page import BaiduPage 5 6 7 class TestBaiduSearch(unittest.TestCase): 8 9 @classmethod 10 def setUpClass(cls): 11 cls.driver = webdriver.Chrome() 12 cls.base_url = "https://www.baidu.com" 13 14 def test_baidu_search_case(self): 15 page = BaiduPage(self.driver) 16 page.open() 17 page.search_input("selenium") 18 page.search_button() 19 sleep(2) 20 self.assertEqual(page.get_title(), "selenium_百度搜索") 21 22 @classmethod 23 def tearDownClass(cls): 24 cls.driver.quit() 25 26 27 if __name__ == '__main__': 28 unittest.main(verbosity=2)