6. 页面对象

本章是一个针对页面对象设计模式的教程引导。一个页面对象表示在你测试的WEB应用程序的用户界面上的区域。

使用页面对象模式的好处:

  • 创建可复用的代码以便于在多个测试用例间共享
  • 减少重复的代码量
  • 如果用户界面变化,只需要修改一处

6.1. 测试用例

下面是一个在python.org网站搜索一个词并保证一些结果可以找到的测试用例。

  1. import unittest
  2. from selenium import webdriver
  3. import page
  4.  
  5. class PythonOrgSearch(unittest.TestCase):
  6. """A sample test class to show how page object works"""
  7.  
  8. def setUp(self):
  9. self.driver = webdriver.Firefox()
  10. self.driver.get("http://www.python.org")
  11.  
  12. def test_search_in_python_org(self):
  13. """
  14. Tests python.org search feature. Searches for the word "pycon" then verified that some results show up.
  15. Note that it does not look for any particular text in search results page. This test verifies that
  16. the results were not empty.
  17. """
  18.  
  19. #Load the main page. In this case the home page of Python.org.
  20. main_page = page.MainPage(self.driver)
  21. #Checks if the word "Python" is in title
  22. assert main_page.is_title_matches(), "python.org title doesn't match."
  23. #Sets the text of search textbox to "pycon"
  24. main_page.search_text_element = "pycon"
  25. main_page.click_go_button()
  26. search_results_page = page.SearchResultsPage(self.driver)
  27. #Verifies that the results page is not empty
  28. assert search_results_page.is_results_found(), "No results found."
  29.  
  30. def tearDown(self):
  31. self.driver.close()
  32.  
  33. if __name__ == "__main__":
  34. unittest.main()

6.2. 页面对象类

页面对象为每个网页模拟创建出一个对象。按照此技术,在测试代码和技术实施之间的一个分离层被创建。

这个 page.py 看起来像这样:

  1. from element import BasePageElement
  2. from locators import MainPageLocators
  3.  
  4. class SearchTextElement(BasePageElement):
  5. """This class gets the search text from the specified locator"""
  6.  
  7. #The locator for search box where search string is entered
  8. locator = 'q'
  9.  
  10.  
  11. class BasePage(object):
  12. """Base class to initialize the base page that will be called from all pages"""
  13.  
  14. def __init__(self, driver):
  15. self.driver = driver
  16.  
  17.  
  18. class MainPage(BasePage):
  19. """Home page action methods come here. I.e. Python.org"""
  20.  
  21. #Declares a variable that will contain the retrieved text
  22. search_text_element = SearchTextElement()
  23.  
  24. def is_title_matches(self):
  25. """Verifies that the hardcoded text "Python" appears in page title"""
  26. return "Python" in self.driver.title
  27.  
  28. def click_go_button(self):
  29. """Triggers the search"""
  30. element = self.driver.find_element(*MainPageLocators.GO_BUTTON)
  31. element.click()
  32.  
  33.  
  34. class SearchResultsPage(BasePage):
  35. """Search results page action methods come here"""
  36.  
  37. def is_results_found(self):
  38. # Probably should search for this text in the specific page
  39. # element, but as for now it works fine
  40. return "No results found." not in self.driver.page_source

6.3. 页面元素

这个 element.py 看起来像这样:

  1. from selenium.webdriver.support.ui import WebDriverWait
  2.  
  3.  
  4. class BasePageElement(object):
  5. """Base page class that is initialized on every page object class."""
  6.  
  7. def __set__(self, obj, value):
  8. """Sets the text to the value supplied"""
  9. driver = obj.driver
  10. WebDriverWait(driver, 100).until(
  11. lambda driver: driver.find_element_by_name(self.locator))
  12. driver.find_element_by_name(self.locator).send_keys(value)
  13.  
  14. def __get__(self, obj, owner):
  15. """Gets the text of the specified object"""
  16. driver = obj.driver
  17. WebDriverWait(driver, 100).until(
  18. lambda driver: driver.find_element_by_name(self.locator))
  19. element = driver.find_element_by_name(self.locator)
  20. return element.get_attribute("value")

6.4. 定位器

其中一个做法是,从它们正在使用的地方分离定位字符。在这个例子中,同一页面的定位器属于同一个类。

这个 locators.py 看起来像这样:

  1. from selenium.webdriver.common.by import By
  2.  
  3. class MainPageLocators(object):
  4. """A class for main page locators. All main page locators should come here"""
  5. GO_BUTTON = (By.ID, 'submit')
  6.  
  7. class SearchResultsPageLocators(object):
  8. """A class for search results locators. All search results locators should come here"""
  9. pass