Turnip を使ったテスト作成のノウハウ

現在、バリバリと Tunip + Capyabara + PhantomJS (poltergeist) で end-to-end テストを書いてます。 そこで知ったノウハウを書きます、今回はテストの構成分けなどの上流側ではなく、ツールや steps 側になります。

f:id:yuum3:20160108112329j:plain

Turnipに限らず Cucmber, RSpec Feature など Capybara を使った、テストの大部分は

  • CSSセレクター(XPath)を使いDOM上のinput、ボタン等を特定し、値の設定やクリックを行う
  • CSSセレクター(XPath)を使いDOM上の表示等で使われる要素を特定し、内容を確認する

の繰り返しです。

ツール

Chrome等のDevTools

まずDOM上のエレメントを特定するための正しく、かつメンテンス生の高いCSSセレクターを決めないと行けません。これは ブラウザーの開発ツール (Cmd+Opt+I)のElements画面で、エレメント選択(Cmd+Shift+C)で画面上の目的の場所をクリックして目的の CSSセレクター を探していけると思います。

また開発ツールの Console を使うと、document.querySelector() や jQueryCSSセレクターが 正しいかを確認できます。 よくあるのは CSSセレクターがユニークでは無く違う要素が選択されてしまう事があるで、単純なCSSセレクター以外は試してみるのが良いです。

正し、jQueryCSSセレクターには拡張があります、これはCapybaraでは動作しないので注意して下さい。

Snapshot

テストが上手く行かない時は表示要素の特定用CSSセレクターの間違だけではなく、対象のページまで来てなかったりJavaScriptが正しく動作してないなどの事もよくあります。 Capybara-WebkitやPoltergeistには現在のDOM(画面)を画像やHTMLとして保存できます。

これを使い以下のようなメソッドやstepsを定義すると、stepsの中や feature の中から呼び出す事で画面を確認できます。

  • helper
def take_screenshot(save_type = :image, path = nil)
  path = Time.now.strftime("/tmp/%y%m%d-%H%M%S-%L.png") unless path

  if save_type == :image
    page.save_screenshot(path)
  else
    File.write(path, page.html)
  end
end
  • steps
step 'HTML保存' do
  take_screenshot(:html)
end

step '画面画像保存' do
  take_screenshot
end

失敗時の Snapshot

以下のような設定を書くと、テストが失敗した時に自動的に Snapshot をとる事ができ失敗の原因追求にとても役立ちます。

RSpec.configure do |config|

  ・・・

  config.after(type: :feature) do |example|
    DatabaseCleaner.clean
    take_screenshot if example.exception.present?
  end

ログ出力

steps は Ruby のコードなので、 p 等でデバック情報をコンソールに出力出来ます。

また、テスト対象の画面にあるJavaScript中に console.log() を書くとやはりコンソールに出力されるのでAjaxからみの複雑な機能のテスト作成に役立ちます。

steps ノウハウ

findの match オプション

page.find()メソッドはデフォルトでは多数がマッチするとエラーになります。CSSセレクターを工夫することでも対処しなくとも、絶対に最初にマッチしたものが正解の場合は以下のように match オプションを指定して逃げる事も出来ます。

  page.find("form input[name='email']", match: :first)

findの visible オプション

page.find()メソッドはデフォルトでは表示されている要素しかマッチしませんが、非表示の要素の値を変更したい場合がありますが、そのような場合は以下のように visible オプションを指定することで可能になります。

  page.find("form input[name='email']", visible: :all)

他のステップの利用

step はrubyメソッドでは無いので、単純には呼び出せませんが、 Calling steps from other steps に書いてあるように、

  • feature に書くように文字列を渡す step メソッド
  • パラメータ(placeholder)を渡し易い send メソッド

の2つを適宜、使い分けると良いと思います。

step 'メール :email パスワード :password ででログイン' do |email, password|
  ...
end

step '社員Aのログイン' do
  step "メール 'a@kaisya.com' パスワード 'PDB4oq4X' ででログイン"
end

step 'ある社員のログイン' do
  send 'メール :email パスワード :password ででログイン',  "e#{rand(1000)}@kaisya.com", "PDB4oq4X"
end

その他

画面サイズ

アプリによってはCapyabara-Webkit画面サイズ(1024 x 768)では一部表示されない場合があるかもしれません。画面サイズは以下のようにして指定できます。

Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, window_size: [1280, 1024])
end



ここに書いたノウハウは、検索すると stackoverflow, qiita, ブログ等に書かれています。それらの情報を書いて頂いた方に感謝いたします。