页面对象
页面对象模式是一种用可重用类表示页面及其元素的方法。页面对象通过构建一个抽象来消除重复,使你能够编写浏览器测试以实现最大的可维护性和健壮性。
页面对象模式起源于 WebDriver,可以在 此处 找到一个很好的解释(带有 Java 中的示例)。
为应用程序的每个页面创建一个页面对象,该对象具有表示给定页面上可用服务的方法。你应该将系统的全部实现细节(即 HTML 元素、等待 DOM 更新等)封装在这些对象中。你的测试代码(即 RSpec 代码块、Cucumber 步骤定义)永远不应访问基础浏览器实例或直接处理 HTML 元素。
从本质上讲,你应该有这样的心态:如果你的 Web 应用程序被重写为桌面应用程序,你的测试代码不应该需要更改 - 你只需要页面对象层的另一个实现即可。虽然严格来说,一组页面不一定是对桌面应用程序进行建模的好方法,但牢记这一点可以很容易地决定什么应该放在哪里。
以下示例假设你熟悉 RSpec 执行测试断言的方式。
考虑此脚本
browser = Watir::Browser.new
browser.goto "http://example.com/login"
browser.text_field(:name => "user").set "Mom"
browser.text_field(:name => "pass").set "s3cr3t"
browser.button(:id => "login").click
Watir::Wait.until { browser.title == "Your Profile" }
browser.div(:id => "logged-in").should exist
使用页面对象,这可能会变成
site = Site.new(Watir::Browser.new)
login_page = site.login_page.open
user_page = login_page.login_as "Mom", "s3cr3t"
user_page.should be_logged_in
其实现可以是
class BrowserContainer
def initialize(browser)
@browser = browser
end
end
class Site < BrowserContainer
def login_page
@login_page = LoginPage.new(@browser)
end
def user_page
@user_page = UserPage.new(@browser)
end
def close
@browser.close
end
end # Site
class LoginPage < BrowserContainer
URL = "http://example.com/login"
def open
@browser.goto URL
self
end
def login_as(user, pass)
user_field.set user
password_field.set pass
login_button.click
next_page = UserPage.new(@browser)
Watir::Wait.until { next_page.loaded? }
next_page
end
private
def user_field
@browser.text_field(:name => "user")
end
def password_field
@browser.text_field(:name => "pass")
end
def login_button
@browser.button(:id => "login")
end
end # LoginPage
class UserPage < BrowserContainer
def logged_in?
logged_in_element.exists?
end
def loaded?
@browser.title == "Your Profile"
end
private
def logged_in_element
@browser.div(:id => "logged-in")
end
end # UserPage
然后可以将其与其他工具集成。例如,使用 Cucumber,你可以在 env.rb 中拥有以下内容
require "watir-webdriver"
require "/path/to/site"
module SiteHelper
def site
@site ||= (
Site.new(Watir::Browser.new(:firefox))
)
end
end
World(SiteHelper)
以及此步骤定义
Given /I have successfully logged in/ do
login_page = site.login_page.open
user_page = login_page.login_as "Mom", "s3cr3t"
user_page.should be_logged_in
end
断言/期望应保存在你的测试代码中。不要在页面对象中使用断言;而是询问它们的状态,并对结果进行断言。例如
#
# bad example
#
class SomePage
def assert_loaded
raise "not loaded" unless some_element.exists?
end
end
it "should be loaded" do
page.assert_loaded
end
#
# good example
#
class SomePage
def loaded?
some_element.exists?
end
end
it "should be loaded" do
page.should be_loaded
end
另请参阅
与 Watir-webdriver 配合使用的页面对象 gem
- Cheezy 的适用于 Watir-webdriver 和 Selenium 的页面对象 gem
- 使用 Watir-webdriver 的页面和数据对象的 rSmart Test-Factory gem
- WatirPump:页面对象 gem - 2018 年的新方法
与页面对象和 Watir-webdriver 相关的博客文章
- cheezyworld 的 UI 测试系列 第 1 部分、第 2 部分、第 3 部分、第 4 部分、第 5 部分
- 西瓜博客文章“自己动手”页面对象
- WatirPump:Ruby 和 Watir 的页面对象库
与页面对象和 webdriver/Selenium 相关的博客文章