自動テスト実施による費用対効果の洗い出し
なぜやるのか
自動化により、テストのコストを下げるため。
どうやるのか
RSpec + Capybara + Selenium ( + Poltergeist + FactoryGirl )
それはなに
- RSpec
- Capybara
- Webブラウザによるテストを手助けしてくれる受け入れテストツールの一つ。
- Poltergeist
- PhantomJSのためのCapybaraのドライバー。Headless(ブラウザを起動しない)でテストケースを実行可能。
- FactoryGirl
- テストデータを自由に扱える(登録、削除が行える)ドライバー。
自動テストで何ができるのか
- ブラウザ別でのUIテスト実施
- CapybaraによるUI操作
- 遷移
- クリック
- 要素の存在有無
- スクリーンショット取得(パスを指定しない場合、プロジェクト直下)
- ファイルアップロード
つまり
- 遷移確認
- ボタン表示
- 文言確認
- バリデーション
のみ自動テストで実行可能。
手動でのテスト実施が好ましいのは
課題は?
- IEでの検証(可能)
- テストケースの見易さの改善、設定ファイルの整理
- SP実機でのケース実行
- DatabaseCleaner, FactoryGirl(DBの操作ツール)の導入(毎回データ登録後削除しなければならないため)
- Jenkinsなどのメンテナンスツールの導入
費用対効果の検証
単純な人件費
初期は手動でのケース作成の3倍と言われている。
その他に
- 保守、サポート費用
- 新規ツール導入費用
- バージョンアップ費用
- 教育、マニュアル費用
などが含まれる。
初動
初めて自動テストケースを書く粒度として
- サービスを動かす上で、最低限動かないと致命的なところ(受け入れテストレベル)
- ユーザーがUIで操作する最低限の遷移、動作
を担保する。
テストケース作成
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 value
は matcherと呼ばれます。
to
や to_not
や not_to
は methodと呼ばれます。
to_not
と not_to
はどちらも同じメソッドです。お好きなほうをお使い下さい。
どのようにCSSのclassやidを指定するか
以下のように指定できます。
page.find(".btn_class").click
`click` がうまくいかない場合
- findを使う
- withinを使う
click
は通常の手作業よりもものすごく早く動作が行われますので、sleep
などで動作を調整します。
またfind
やwithin
を用いて範囲を指定し、特定の箇所がきちっと押下されるようにフォーカスを行います。
find
、within
どちらも、処理が終わるまで(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
が生成されるため、scenario
、feature
を跨いでログインが持続しない、または全データが引き継がれないということが起こる。
なので、scenario
、feature
を跨がずケースを作成することが望ましい。
複数の同じ要素がある場合に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
を用いることで、scenario
、it
ごとの経過秒数を表示してくれます。
% 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
このエラーの場合は、register
をcurrent
やdefault
へ変更します。
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