Edited at

CapybaraとSeleniumを使ってPageObjectデザインパターンによる画面変更に強いUIテストのサンプル

More than 3 years have passed since last update.


概要

画面操作とテストシナリオが疎結合にできるPageObjectデザインパターンを試したかったので、検索ワードにヒットする商品を自動購入するAmazonの自動購入処理を書きました。

参考ページをCapybaraに移植したものになります。


PageObjectデザインパターンとは

公式によるとPageObjectデザインパターンとは、以下だそうです。


・The public methods represent the services that the page offers(publicメソッドは、ページが提供するサービスを表す)

・Try not to expose the the internals of the page (ページの内部を公開しないこと)

・Generally don’t make assertions (原則としてassertionを行わないこと)

・Methods return other PageObjects (メソッドは他のPageObjectsを返す)

・Need not represent an entire page (ページ全体を表す必要はない)

・Different results for the same action are modelled as different as different methods (同じアクションに対して異なる結果となる場合には異なるメソッドとしてモデル化する)


PageObjectデザインパターンを利用して画面変更に強いUIテストを作成する│ソフトウェアテストラボ


仕様

Amazonのホームから、任意の検索ワードで検索して、商品をカゴに入れて代引きで購入します。


実装

require "capybara"

require "selenium-webdriver"

Capybara.current_driver = :selenium

Capybara.configure do |config|
config.run_server = false
config.app_host = "http://www.amazon.co.jp"
end

id = "example@exmaple.com"
pass = "password"

module Amazon
class Page
include Capybara::DSL
end

class HomePage < Page
def goHome
visit "/"
self
end

def searchItem word
fill_in "field-keywords" , with: word
click_on '検索'
SearchResultPage.new
end
end

class SearchResultPage < Page
def choiceItem num=0
all(".s-item-container")[num]
.find(".a-link-normal.s-access-detail-page.a-text-normal").click
current_window.close
switch_to_window windows[0]
ItemDetailPage.new
end
end

class ItemDetailPage < Page
def addToShoppingCart
sleep 2
all("[id='add-to-cart-button']")[0].click
RecommendPage.new
end
end

class RecommendPage < Page
def goCart
find("#hlb-ptc-btn-native").click
LoginPage.new
end
end

class LoginPage < Page
def login id, password
fill_in 'email' , with: id
fill_in 'password' , with: password
find("#signInSubmit-input").click
DeliveryPage.new
end
end

class DeliveryPage < Page
def choiceAddress num=0
all("a.a-declarative.a-button-text")[num].click
sleep 3
DeliveryOptionPage.new
end
end

class DeliveryOptionPage < Page
def goNextPage
first(".a-button-text").click
sleep 3
PaymentPage.new
end
end

class PaymentPage < Page
def goNextPage
first(".a-button-text").click
sleep 2
ConfirmationPage.new
end

def changeOption option
if option == :cod
first("div.radio-col.spacing-right-small > input[value='cashOnDeliveryCash']").set(true)
end
self
end
end

class ConfirmationPage < Page
def decision
save_screenshot('screenshot.png')
first(".a-button-text.place-your-order-button").click
end
end

end

Amazon::HomePage.new
.goHome
.searchItem("Selenium")
.choiceItem
.addToShoppingCart
.goCart
.login(id, pass)
.choiceAddress(0)
.goNextPage
.changeOption(:cod)
.goNextPage
.decision


まとめ

スクレイピングするのが好きなのですが、ページオブジェクトパターンは返り値としてページオブジェクトを使うのでルールに準拠するとスクレイピングには使えないですね。

ほどよく、UI操作とシナリオを分割してコード書きたいです。


参考文献


注意

Kindleの商品の場合、カートに入れるボタンが無いなど、一部動かない場合があります。

サンプルということで。

住所はすでに登録されているものとして、進めています。