Cucumber 和 Capybara 下的 PageObject

接上篇 由 step definition 失控引发的讨论和思考

PageObject

先来看下目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
.
├── Gemfile
├── Gemfile.lock
├── README
├── Rakefile
├── cucumber.yml
├── features
│   ├── example
│   │   ├── example.feature
│   │   ├── step_definitions
│   │   │   └── example_steps.rb
│   │   └── support
│   │   └── env.rb
│   └── blog_project
│   ├── user_management
| | |--- login.feature
| | |--- logout.feature
│   ├── post_management
| | |--- write_a_post.feature
│   ├── upload_image.feature
│   ├── pages
│   │   ├── login_page.rb
│   │   └── post_page.rb
│   ├── step_definitions
│   │   ├── post_step.rb
│   │   ├── user_step.rb
│   │   ├── common_steps.rb
│   └── support
│   ├── env.rb
│   └── helper
│   └── path.rb
└── features_report.html
  1. 把 features 按照模块用目录分类。
  2. 将 page object 放在 pages 目录下。
  3. 每一个模块一个 step definition rb 文件。
  4. 在 support 里配置各种环境啊,hook啊,帮助类等。

其实无论你怎么写, cucumber 运行的时候,都会把这些 rb 一股脑儿加载进来。所以对于
cucumber 来说什么样子的目录结构对它无所谓,所以对我们而言,只要方便管理就可以了。

现在我们就要在 pages 这个目录做文章。在 cucumber 下使用 pageobject 一般有两种方法:

1. 自己封装

自己封装 pageobject 的过程其实就是把 webdriver page object java 的那一套翻译成 ruby。

  • 提取页面元素
  • 封装页面业务逻辑

比如:

login_page.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class LoginPage
URL = "/login"
def initialize(session)
@session = session
end
def visit
@session.visit URL
end
def username_input_element
@session.find "input[name=username]"
end
def password_input_element
@session.find "input[name=password]"
end
def login name, password
username_input_element.type name
password_input_element.type password
@session.click_button("login")
end

login_stepdef.rb

1
2
3
4
5
6
7
8
Given /^I am in the home page$/ do
@login_page = LoginPage.new(Capybara.current_session)
@login_page.visit
end
When /^I login with usernmae "test" and password "test"$/ do |name, password|
@login_page.login name, password
end

2. 使用现成的 gem

ruby 界最不缺的就是第三方实现了。github 里一搜一大把。

我最早用的是 cheezy/page-object

>

  1. A Simple DSL you can use to define and interact with the content on your page
  2. Support for both watir-webdriver and selenium-webdriver
  3. An easy way of creating and using page objects in your cucumber steps or in rspec
  4. A Simple way of dealing with Frames and iFrames
  5. Robust way of dealing with Ajax Calls
  6. A clean way of handling Javascript Popups
  7. Support for most html Elements

使用非常简单:

login_page.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
class LoginPage
include PageObject
text_field(:username, :id => 'username')
text_field(:password, :id => 'password')
button(:login, :id => 'login')
def login_with(username, password)
self.username = username
self.password = password
login
end
end

login_stepdef.rb

1
2
3
4
5
6
7
8
Given /^I am in the home page$/ do
visit HOME_PATH
@login_page = LoginPage.new(Capybara.current_session)
end
When /^I login with usernmae "test" and password "test"$/ do |name, password|
@login_page.login_with name, password
end

具体可以移步:Get started!

说心里话,如果不是用 capybara 的话, 在 ruby 下写 webdriver 自动化,必然首选 cheezy/page-object

我们这次选择了 SitePrism

A Page Object Model DSL for Capybara
SitePrism gives you a simple, clean and semantic DSL
for describing your site using the Page Object Model pattern, for use with Capybara in automated acceptance testing.

在 cucumber 中使用 SitePrism 需要加入依赖

1
2
3
4
require 'capybara'
require 'capybara/cucumber'
require 'selenium-webdriver'
require 'site_prism'

其实只要在 Gemfile 中加入以下 gem 即可:

1
2
3
gem "cucumber-rails"
gem "capybara"
gem "site_prism", "~> 2.4"

使用同样非常简单:

login_page.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
class LoginPage < SitePrism::Page
set_url "/login"
element :username_input_field, "input[name='username']"
element :password_input_field, "input[name='password']"
element :login_button, "button[name='login']"
def login_with username, password
username_input_element.type username
password_input_element.type username
login_button.click
end
end

login_stepdef.rb

1
2
3
4
5
6
7
8
Given /^I am in the home page$/ do
@login_page = LoginPage.new # 不用传 driver 哦~
@login_page.load
end
When /^I login with usernmae "test" and password "test"$/ do |name, password|
@login_page.login_with name, password
end

Summary

可以看得出,page object 的方案还是很多的,自己定义比较灵活,轻巧,使用 gem 可以省去不少心思。
个人建议是,使用 gem, 如果gem 无法完成的,再上自己封装!

文章目录
  1. 1. PageObject
    1. 1.1. 1. 自己封装
    2. 1.2. 2. 使用现成的 gem
      1. 1.2.1. 我最早用的是 cheezy/page-object
      2. 1.2.2. 我们这次选择了 SitePrism
  2. 2. Summary
|