Edited at

Rails + Turnip + Capybara + poltergeistでBDDテスト

More than 5 years have passed since last update.

ちょっとテストコードを見直す機会があったのでこの機会にTurnipを入れてGherkinで記述する事でより、第三者が見やすいようにしてみた。

その際に色々調べたのでメモ。


1 Turnipってなんぞや?

簡単にいうと、

・大枠はCucumberと同じ

・Cucumberの際に一番ネックとなっていた正規表現の部分をよりプレースホルダーを使って簡単に記述

・Capybaraの開発者が作ったものなので、Capybaraとの相性は申し分なし


2 Gherkin書式ってなんぞや?

・ Cucumber により拡張された書式。Business Readable DSL(≒仕様記述のDSL)といわれている

・システムの振る舞いを記述するための自然言語に近い書式

(下記の実際のコードを見てもらえれば理解できるかと思います)

※ちなみに...有名な他のDSLとしは、

Rspec :テストのDSL

Chef :システムアドミニストレーションのDSL

Fluentd:マシン間配送のDSL

Capybara: e2e検証のDSL


3 導入


1 インストール

group :developmentm :test do

gem "turnip"
end

bundle install


2 設定ファイル

今回はcapybaraのdriverとしてpoltergeistを使ってます。

※poltergeistのインストールは下記を参考にしていただければw

http://d.hatena.ne.jp/ria10/20130122/1358836316

http://qiita.com/katryo/items/e33197a4fa26de42a3c4


spec/turnip_helper.rb

require 'turnip'

require 'turnip/capybara'
require 'turnip/rspec'
require 'capybara'
require 'capybara/poltergeist'

#各種driverの設定
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, {:js_errors => false, :default_wait_time => 30, :timeout => 100})
end

#mobileのuseragent
Capybara.register_driver :mobile do |app|
Capybara::RackTest::Driver.new(app,
:headers => {'HTTP_USER_AGENT' => '※適宜好きなものを'})
end

#pcのuseragent
Capybara.register_driver :pc do |app|
Capybara::RackTest::Driver.new(app,
:headers => {'HTTP_USER_AGENT' => '※適宜好きなものを'})
end

Capybara.configure do |config|
config.default_driver = :pc
config.javascript_driver = :poltergeist
config.ignore_hidden_elements = true
config.default_wait_time = 30
end

Dir.glob("spec/**/*steps.rb") { |f| load f, true }



3 テストを書いていく

turnipでは、

・spec/features/*.featureという機能を記述するファイル

→機能 (とストーリー)、シナリオ、ステップの 3 階層で記述します

・/spec/steps/*.steps.rbというテストシナリオで実施する具体的な手続きを記述するファイル

という大きく2つの構成で成り立ちます。


・featureファイル


spec/features/hoge.feature


# encoding: utf-8
# language: ja

@common
機能: hoge機能
hoge機能のテストを行っています。
hoge、fugaの両パターンにてテストしてます。

背景:
前提 PCを利用している

@hoge
シナリオ: topを訪問しhogehogeすると成功
もし topを訪問
かつ hogehogeボタンをクリック
ならば hoge成功

@fuga
シナリオ: topを訪問しhogehogeすると成功
もし helpを訪問
かつ fugafugaをフォームに入力
ならば hoge成功


最初から説明していくと、

まず今回は日本語で記述しているので、下記を記述する必要があります。

# language: ja  

大きくfeatureファイルを構成するものとしては下記4つで、


・機能

→'hoge機能'


・背景(※なくても問題ない)

→'前提 PCを利用している'


・ストーリー(※なくても問題ない)

→'hoge機能のテストを行っています。hoge、fugaの両パターンにてテストしてます。'


・シナリオ

→'topを訪問しhogehogeすると成功'


・ステップ

→' もし〜...ならば 〜'

上記のソースで当てはめるとこのようになります。

@common @hoge @fuga 

これはタグと言われるものです。

あとでsteps.rbを見ていただけると分かりますが、

steps_for :common do

@common が付いているシナリオのみに適用
end

てな感じで、特定のものを適用させたい際につけるようです。

覚えるfeatureで使うstepの予約語としては下記ぐらいかと。

日本語
英語

前提
Given

もし
When

ならば
Then

かつ
And

ちなみに、「前提」、「もし」、「ならば」は同じ挙動のようですw


・stepファイル

featureファイルに対応するのがstepファイル。


spec/steps/hoge_steps.rb

# encoding: utf-8

steps_for :common do

step ':page_name を訪問' do |page_name|
url = "http://127.0.0.1/#{page_name}"
visit url
end

step 'hoge成功' do
expect(page).to have_content("hoge成功")
end
end

steps_for : hoge do

step 'hogehogeボタンをクリック' do
find('button#hogehoge').click
end
end

steps_for : fuga do

step 'fugafugaをフォームに入力' do
fill_in 'fugafuga_form', with: 'fugafuga'
end
end


まずそれぞれのシナリオに共通するものはタグで共有化させてしまって、各々で必要なものだけ別に書くような感じ。

例えば、全てのシナリオで使いそうなものに関してはGlobal stepというものを用いて定義しておく。(例:ログイン機能とか)

また汎用的に出来るものはプレースホルダーを使って実装。

step ':page_name を訪問' do |page_name|

end

moduleを使った方が良いものに関しては、

https://github.com/jnicklas/turnip/blob/master/examples/steps/alignment_steps.rb

このようにmoduleを使って実装する。


4 詰まったところ

①1featureファイルに2シナリオ以上記載するとなぜかjavascriptのdriverが選ばれてないとエラーが出た。。。

→背景の部分で前提を定義しておき、シナリオ毎に呼び出して対応(下記のような形)

step 'PCを利用している' do

Capybara.current_driver = :poltergeist
end

②同じstep名を定義できないので、すぐに重複してうのではという疑問があった。

→基本的なものは共通ファイルに定義して、各々で使うものはsteps_forで定義して使えば問題なさそう。


5 最後に...

個人的には、良いと思った点は

・すごく読みやすい

→別のメンバーが実装したテストも、どういうシナリオで何を行っているのかが分かるので理解しやすい

・ドキュメント的な位置づけにもなりそう

→駆け出しサービスは特に仕様をまとめたドキュメントなど作ってないと思うので、Gherkinでテストを書いておけば、ドキュメントの位置づけにもなるかと


6 参考

jnicklas / turnip

エンドツーエンドテストの自動化は Cucumber から Turnip へ

Ruby on Rails / Turnip / Capybara / Spork / poltergeist の利用設定