初识Page Object
PageObject是UI自动化测试项目开发实践的最佳设计模式之一,它的主要特点体现在对界面交互细节的封装上,使测试用例更加专注于业务的操作,从而提高测试用例的可维护性。
1.认识Page Object
Page Object设计模式的优点:
- 减少代码的重复
- 提高测试用例的可读性
- 提高测试用例的可维护性,特别是针对UI频繁变化的项目;
Page Object应遵循以下原则进行开发:
- Page Object应该易于使用
- 有清晰的结构,如PageObject对应页面对象,PageModules对应页面内容
- 只写测试内容,不写基础内容
- 在可能的情况下放置样板代码
- 不需要自己管理浏览器
- 在运行时选择浏览器,而不是类级别
- 不需要直接接触Selenium
Page Object简单实例:
已百度搜索为例,假设我们有如下测试代码:
import unittest from selenium import webdriver from selenium.webdriver.common.by import By class Test(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome() self.base_url = 'http://www.baidu.com' def test_baidu_search_case1(self): self.driver.get(self.base_url) self.driver.find_element(By.ID, 'kw').send_keys('unittest') self.driver.find_element(By.ID, 'su').click() def test_baidu_search_case2(self): self.driver.get(self.base_url) self.driver.find_element(By.ID, 'kw').send_keys('selenium') self.driver.find_element(By.ID, 'su').click() def test_baidu_search_case3(self): self.driver.get(self.base_url) self.driver.find_element(By.ID, 'kw').send_keys('page object') self.driver.find_element(By.ID, 'su').click() def tearDown(self): self.driver.quit() if __name__ == '__main__': unittest.main()
这段代码最大的问题就是三条测试用例中重复使用了元素的定位和操作。这会带来一个很大的问题,当元素的定位发生变化后,例如id=kw失效了,应及时调整整个定位方法,这时就需要三条测试用例分别进行更改。假设,我们的自动化不止3条测试用例,而UI不断变化,那么就会提高自动化测试用例的维护成本。
Page Object的设计思想上是把元素定位于元素操作进行分层,这样带来的最直接的好处就是当元素发生变化时,只需要维护page层的元素定位,而不需要关心在哪些测试用例当中使用了这些元素。在编写测试用例时,也不需要关心元素是如何定位的。
上面代码进行优化:
from selenium.webdriver.common.by import By class BaiduPage: def __init__(self, driver): self.driver = driver def search_input(self, search_key): self.driver.find_element(By.ID, 'kw').send_keys(search_key) def search_button(self): self.driver.find_element(By.ID, 'su').click()
首先,创建了一个BaiduPage类,在__init__()初始化方法中接受参数driver并赋值给self.driver。然后分别封装了search_input()和search_button()方法,定位并元素操作。这里的封装只针对一个页面中可能会操作到的元素,原则上是一个元素封装成一个方法。当元素的定位方法发生改变时,只需要维护这里的方法即可。而不需要关心这个方法被那谢谢测试用例使用了。
使用:
import unittest from selenium import webdriver from selenium.webdriver.common.by import By from samples.baidu_page import BaiduPage class Test(unittest.TestCase): def setUp(self): self.driver = webdriver.Chrome() self.base_url = 'http://www.baidu.com' def test_baidu_search_case1(self): self.driver.get(self.base_url) bd = BaiduPage(self.driver) bd.search_input('selenium') bd.search_button() def test_baidu_search_case2(self): self.driver.get(self.base_url) bd = BaiduPage(self.driver) bd.search_input('unittest') bd.search_button() def test_baidu_search_case3(self): self.driver.get(self.base_url) bd = BaiduPage(self.driver) bd.search_input('page object') bd.search_button() def tearDown(self): self.driver.quit() if __name__ == '__main__': unittest.main()
首先在测试中导入BaiduPage类,然后在每个测试用例中为BaiduPage类传入 驱动,这样就可以轻松地使用它封装的方法来设计具体的测试用例了。这样做的目的就是在测试用例中消除元素定位。如果你要操作百度输入框,那么只需要调用search_input()方法并传入搜索关键字即可,并不需要再重新编写定位元素。
备注:这样的方法带来了许多好处,但是也带来了一些问题。例如,需要些更多的代码。以前一条测试用例只需要写4到5行代码即可,现在却不得不现在Page层次对每个带操作的元素进行封装,然后在到具体的测试用例的引用。
备注:学习selenium3 自动化测试实战