CapybaraによるUI自動化ドキュメント

自動テスト実施による費用対効果の洗い出し

なぜやるのか

自動化により、テストのコストを下げるため。


どうやるのか

RSpec + Capybara + Selenium ( + Poltergeist + FactoryGirl )

それはなに
  • RSpec
  • Capybara
    • Webブラウザによるテストを手助けしてくれる受け入れテストツールの一つ。
  • Poltergeist
    • PhantomJSのためのCapybaraのドライバー。Headless(ブラウザを起動しない)でテストケースを実行可能。
  • FactoryGirl
    • テストデータを自由に扱える(登録、削除が行える)ドライバー。

BDDとは?

「振る舞い」や「制約条件」、つまり「要求仕様」に近い形で、自然言語を併記しながらテストコードを記述する。

Wikipedia


自動テストで何ができるのか

  • ブラウザ別でのUIテスト実施
  • CapybaraによるUI操作
    • 遷移
    • クリック
    • 要素の存在有無
    • スクリーンショット取得(パスを指定しない場合、プロジェクト直下)
    • ファイルアップロード


つまり

  • 遷移確認
  • ボタン表示
  • 文言確認
  • バリデーション

のみ自動テストで実行可能。


手動でのテスト実施が好ましいのは

  • 最大・最小値、画像などのレイアウト確認
  • 新しくタブが開く動作
  • CSVやPDFなどのダウンロードして確認する内容
  • バッチを叩く動作
  • 日付を跨いでの確認
  • SNSのシェア


課題は?

  • IEでの検証(可能)
  • テストケースの見易さの改善、設定ファイルの整理
  • SP実機でのケース実行
  • DatabaseCleaner, FactoryGirl(DBの操作ツール)の導入(毎回データ登録後削除しなければならないため)
  • Jenkinsなどのメンテナンスツールの導入


費用対効果の検証

単純な人件費

初期は手動でのケース作成の3倍と言われている。

Selenium導入ガイドラインなど


その他に
  • 保守、サポート費用
  • 新規ツール導入費用
  • バージョンアップ費用
  • 教育、マニュアル費用

などが含まれる。


初動

初めて自動テストケースを書く粒度として

  • サービスを動かす上で、最低限動かないと致命的なところ(受け入れテストレベル)
  • ユーザーがUIで操作する最低限の遷移、動作

を担保する。


環境構築〜テスト実施まで


Ruby環境の設定

hrt0kmt.hatenablog.com


テストケース作成

require "selenium-webdriver"
require 'capybara/rspec'
require 'pry'

# Set Capybara DSL on RSpec
RSpec.configure do |config|
config.include Capybara::DSL
end

# Use Selenium on Capybara
Capybara.default_driver = :selenium
Capybara.app_host = 'http://xxx.com'

# example group layer
describe "test" do

    # example layer
    it "To show a login page" do
        expect(page).to have_content('ログイン')
    end
end

# conditional branching
describe Test2 do
    # example group
    describe "login" do
        # context A
        context "Case of A" do
            # example
            it "xxxxxxxx" do
                expect(user).to eq "xxxxxxxx"
            end
        end
        # context B
        context "Case of B" do
            # example
            it "xxxxxxxx" do
                expect(user).to eq "xxxxxxxx"
            end
        end
    end
end


設定ファイルまでのパス

/{project_folder}/{project}/vendor/bundle/ruby/2.2.0/gems/capybara-2.4.4/spec/spec_helper.rb


用語整理

example = specify = it

context は条件分岐の場合に用います。

  • describe = feature
  • it = scenario = example = specify
  • before = background

feature spec = E2E test

before は、exampleの実行前に毎回呼び出されるメソッドです。


matcherとはなにか

expect(`procedure`).to eq `expected value`

expect(`procedure`).not_to eq `expected value`

expected valuematcherと呼ばれます。

toto_notnot_tomethodと呼ばれます。

to_notnot_to はどちらも同じメソッドです。お好きなほうをお使い下さい。


どのようにCSSのclassやidを指定するか

以下のように指定できます。

page.find(".btn_class").click


`click` がうまくいかない場合

  1. findを使う
  2. withinを使う

clickは通常の手作業よりもものすごく早く動作が行われますので、sleepなどで動作を調整します。

またfindwithinを用いて範囲を指定し、特定の箇所がきちっと押下されるようにフォーカスを行います。

findwithinどちらも、処理が終わるまで(HTMLの要素を見つけるまで)待機します。


メソッド一覧

メソッド 内容
visit {path} move page
sleep stop(minute)
click_button '確認' click button name
click_link 'id-xxx' click link by id
click_link 'text...' click link text
click_on 'link or button' click link or button
fill_in 'email', with:'test@test.com' insert email=name element
choose '選択肢D' select radio button
select 'D', from:'name-el' select pull down
expect(page).to have_content 'ログイン' search 'ログイン' text
within ".thumb" do ~ end focus in .thumb class (eq find)
check '同意する' select check button


オプション

セッションが切れる

require "capybara/rspec"itを行う毎にCapybara.current_sessionが生成されるため、scenariofeatureを跨いでログインが持続しない、または全データが引き継がれないということが起こる。

なので、scenariofeatureを跨がずケースを作成することが望ましい。


複数の同じ要素がある場合にCapybaraが該当の要素を見つけられない

最初の要素を指定したい(ボタンをクリックさせたい)場合は...

first(:link, '詳細').click


スルーさせたいテストがある

xを接頭に付与することによりスキップが可能です。

    xscenario "ログインログアウト" do
        visit '/login'
        expect(page).to have_content('ログイン')
        fill_in 'email', with:'test@com'
        fill_in 'password', with:'password'
        click_button 'ログイン'
        sleep 1
        expect(page).to have_content 'xxx'
        click_link 'ログアウト'
        sleep 1
    end


コメントアウト=begin=endを用います。

=begin
# Safariドライバー(ローカライズ中)
Capybara.register_driver :selenium_safari do |app|
    Capybara::Selenium::Driver.new(app, :browser => :safari)
end
    if Selenium::WebDriver::Platform.find_binary "safaridriver"
    Capybara.default_driver = :selenium_safari
    else
    Capybara.default_driver = :selenium
end
=end


スローテストを行う

--profileを用いることで、scenarioitごとの経過秒数を表示してくれます。

% bundle exec rspec spice_modify_account.rb --profile 2

Top 2 slowest examples (38.4 seconds, 100.0% of total time):
  アカウント登録フロー アカウント編集
    38.4 seconds ./modify_account.rb:66
  アカウント登録フロー ログインログアウト
    0.00001 seconds ./modify_account.rb:54


wrong number of arguments (1 for 0) (ArgumentError)

1 for 0 というのは,0であるべきところに1あるということであり、引数を変更する必要があります。

# Poltergeist Remote debugging
Capybara.default_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, inspector: true)
end


ArgumentError: rack-test requires a rack application, but none was given

このエラーの場合は、registercurrentdefaultへ変更します。

Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver()
end


Capybara + Poltergeist

  • CapybaraでPhantomJSを使用するためのライブラリが、Poltergeist。
  • Poltergeistはheadless ( Seleniumと違い、ブラウザを起動せずJSが実行できる)ドライバ。
  • SeleniumもJSが実行できるが毎回ブラウザが起動して時間が掛かってしまうため、PhantomJSを使用することにより効率的にテストが可能。
% brew install phantomjs // case of Homebrew
% sudo port install phantomjs // case of MacPorts