页面对象
这章是对 页面对象设计模型的特别指导。一个页面对象代表了你要测试的用户接口交互的区域。
使用页面对象模型的好处: 可以写出能在多个测试案例里复用的代码 减少重复代码 * 如果用户接口更改,只需要在一个地方做相应修改即可
测试案例
下面这个测试案例测试了在python.org
网页上搜索一个单词并确认有相应的搜索结果:
import unittest
from selenium import webdriver
import page
class PythonOrgSearch(unittest.TestCase):
"""一个简单展示页面对象如何工作的类"""
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.get("http://www.python.org")
def test_search_in_python_org(self):
"""
测试 python.org网站的搜索功能。搜索一个单词“pycon”然后验证某些结果会展示出来。
注意这个测试不会在搜索结果页里寻找任何细节文本,它只会验证结果为非空
"""
#载入主页面,这个例子里是 Python.org的首页
main_page = page.MainPage(self.driver)
#检查页面的标题是否包含"python"单词
assert main_page.is_title_matches(), "python.org title doesn't match."
#将搜索框的文本设置为"pycon"
main_page.search_text_element = "pycon"
main_page.click_go_button()
search_results_page = page.SearchResultsPage(self.driver)
#验证结果页非空
assert search_results_page.is_results_found(), "No results found."
def tearDown(self):
self.driver.close()
if __name__ == "__main__":
unittest.main()
页面对象类
页面对象模型旨在给每一个Web页面创造一个对象。运用这个技术我们可以在测试代码和技术实现之间创建一个分离层,page.py
会是这样的:
from element import BasePageElement
from locators import MainPageLocators
class SearchTextElement(BasePageElement):
"""这个类从指定的定位器里获取到搜索文本"""
#已经输入搜索字符串的搜索框的定位器
locator = 'q'
class BasePage(object):
"""初始化所有页面都会调用的基本页类"""
def __init__(self, driver):
self.driver = driver
class MainPage(BasePage):
"""主页操作方法放这里"""
#定义一个变量存放检索文本
search_text_element = SearchTextElement()
def is_title_matches(self):
"""验证硬编码字符"python"出现在页面标题里"""
return "Python" in self.driver.title
def click_go_button(self):
"""触发搜索功能"""
element = self.driver.find_element(*MainPageLocators.GO_BUTTON)
element.click()
class SearchResultsPage(BasePage):
"""搜索结果页操作方法放这里"""
def is_results_found(self):
# 或许应该在具体的页面元素里搜索文本,不过目前为止这样运行没什么问题
return "No results found." not in self.driver.page_source
页面元素
element.py
类大致是这样的:
from selenium.webdriver.support.ui import WebDriverWait
class BasePageElement(object):
"""初始化每个页面对象类的基本页类"""
def __set__(self, obj, value):
"""用给定的值设置文本"""
driver = obj.driver
WebDriverWait(driver, 100).until(
lambda driver: driver.find_element_by_name(self.locator))
driver.find_element_by_name(self.locator).send_keys(value)
def __get__(self, obj, owner):
"""从具体的对象里获取文本"""
driver = obj.driver
WebDriverWait(driver, 100).until(
lambda driver: driver.find_element_by_name(self.locator))
element = driver.find_element_by_name(self.locator)
return element.get_attribute("value")
定位器
One of the practices is to separate the locator strings from the place where they are being used.在这个例子里,同页面的定位器是同一个类
The locators.py will look like this:
from selenium.webdriver.common.by import By
class MainPageLocators(object):
"""一个主页面定位器类,所有的页面定位器应该来自这里"""
GO_BUTTON = (By.ID, 'submit')
class SearchResultsPageLocators(object):
"""一个搜索结果定位器类,所有搜索结果定位器应该来自这里"""
pass