Cucumberのインストール
今回選択した環境は Cucumber + Capybara + Culerity + Rspec + Spork です。さっそくセットアップしていきましょう。
#gemのインストール sudo gem install cucumber cucumber-rails celerity # Culerityで使用するjrubyのインストール sudo apt-get install jruby # JrubyのgemsにCelerityを追加 sudo /usr/lib/jruby1.2/bin/gem install celerity
サンプルプロジェクトの作成
RSSのFeedを登録するだけのアプリケーションを作ってみます。
本編と関係ありませんが、rails projectの名前にsampleという接頭辞をつけておくと大変便利です。新しく機能を導入する際に一回使いきりのプロジェクトを用意して思い切り遊べるようにできるからです。いらなくなったらプロジェクトはrm sample* -rで、DBはdrop database samplexxxx_test; で削除すれば良いので間違いが少なくて済みます。
$ rails -d mysql samplecucmber $ ruby script/generate rspec_scaffold feed url:string : create db/migrate create db/migrate/20100228205558_create_feeds.rb route map.resources :feeds $ rake db:migrate
rails環境のセットアップ
まずは--capybara, --rspecオプションだけをつけた状態で実行します。
$ ruby script/generate cucumber --capybara --rspec #設定ファイル。出力先としてreturn.txtが設定されています。 create config/cucumber.yml #同じく設定ファイルですがCucumber実行時のRails環境の動作と必要なconfig.gemを指定しています create config/environments/cucumber.rb create script/cucumber #cucumber本体の呼び出しスクリプト create features/step_definitions create features/step_definitions/web_steps.rb create features/support create features/support/env.rb #ここにGherkinで書かれたページ名をURLにマップを設定します。 create features/support/paths.rb create lib/tasks #Cucumber関係のrakeタスクを定義 create lib/tasks/cucumber.rake
太字は一番最初のcucumberで扱ったプレーンなCucumber環境と比べて増えたファイルです。
次に--sporkオプションをつけてsporkの設定に必要なファイルを見てみましょう。
$ ruby script/generate cucumber --spork --force overwrite config/cucumber.yml? (enter "h" for help) [Ynaqdh] Y #DRbが出力に追加されました force config/cucumber.yml overwrite config/environments/cucumber.rb? (enter "h" for help) [Ynaqdh] Y #config.gemsporkが追加されました force config/environments/cucumber.rb identical script/cucumber exists features/step_definitions identical features/step_definitions/web_steps.rb exists features/support overwrite features/support/env.rb? (enter "h" for help) [Ynaqdh] Y #require 'spork'が追加されました。requireの記述がSpork.preforkブロックに囲まれました。 force features/support/env.rb identical features/support/paths.rb exists lib/tasks identical lib/tasks/cucumber.rake
次にプロジェクト依存のgemのバージョンをインストールします。この方法で別途gemをインストールするのはgemのバージョンとプロジェクトをそろえて何かの時(人にコードを渡した、しばらくぶりにプロジェクトが再開された)場合にテストを止めないようにするための工夫ではないかと思います。RAILS_ROOT/config/envioronments/cucumber.rbに以下のような記述がありました。どうもここから必要なgemをインストールしている様です。
参考 Ruby on Rails Tips - rake gems:install
#当環境のバージョンは以下のとおり。 #cucumber (0.6.2) #cucumber-rails (0.2.4) config.gem 'cucumber-rails', :lib => false, :version => '>=0.2.4' unless File.directory?(File.join(Rails.root, 'vendor/plugins/cucumber-rails')) config.gem 'database_cleaner', :lib => false, :version => '>=0.4.3' unless File.directory?(File.join(Rails.root, 'vendor/plugins/database_cleaner')) config.gem 'capybara', :lib => false, :version => '>=0.3.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/capybara')) config.gem 'rspec', :lib => false, :version => '>=1.3.0' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec')) config.gem 'rspec-rails', :lib => false, :version => '>=1.3.2' unless File.directory?(File.join(Rails.root, 'vendor/plugins/rspec-rails')) config.gem 'spork', :lib => false, :version => '>=0.7.5' unless File.directory?(File.join(Rails.root, 'vendor/plugins/spork'))
プロジェクト依存のgemをインストールします。
#先に必要なライブラリをインストール sudo aptitude install libxslt1-dev libxml2-dev RAILS_ENV=cucumber rake gems:install
このステップでcapybaraがインストールされるはずです。同時に多くの依存するgemがインストールされるので、gemが依存するライブラリがインストールされていない場合はメッセージを出力してcapybaraのインストールが失敗します。該当ライブラリをインストールしてください。
Cucumberを使ったBDD
featureの作成
#feature 'controllerの名前' :オブジェクト変数(script/generate scaffold で指定するのと一緒) $ ruby script/generate feature feed url:string exists features/step_definitions create features/manage_feeds.feature create features/step_definitions/feeds_steps.rb
それでは試験を開始します。
#sporkサーバを立ち上げます。 $ ~/.gem/ruby/1.8/bin/spork cuc #drbを設定 $ rake cucumber --drb #試験実行 $ rake cucumber (in /home/suzukimilanpaak/workspace/ror/samplecucumber) /opt/ruby-enterprise-1.8.7/bin/ruby -I "/opt/ruby-enterprise-1.8.7/lib/ruby/gems/1.8/gems/cucumber-0.6.2/lib:lib" "/opt/ruby-enterprise-1.8.7/lib/ruby/gems/1.8/gems/cucumber-0.6.2/bin/cucumber" --profile default Using the default profile... Disabling profiles... Feature: Manage feeds In order to [goal] [stakeholder] wants [behaviour] # Rails generates Delete links that use Javascript to pop up a confirmation # dialog and then do a HTTP POST request (emulated DELETE request). # # Capybara must use Culerity or Selenium2 (webdriver) when pages rely on # Javascript events. Only Culerity supports confirmation dialogs. # # cucumber-rails will turn off transactions for scenarios tagged with # @selenium, @culerity, @javascript or @no-txn and clean the database with # DatabaseCleaner after the scenario has finished. This is to prevent data # from leaking into the next scenario. # # Culerity has some performance overhead, and there are two alternatives to using # Culerity: # # a) You can remove the @culerity tag and run everything in-process, but then you # also have to modify your views to use button instead: http://github.com/jnicklas/capybara/issues#issue/12 # # b) Replace the @culerity tag with @emulate_rails_javascript. This will detect # the onclick javascript and emulate its behaviour without a real Javascript # interpreter. # @culerity Scenario: Delete feed # features/manage_feeds.feature:34 Given the following feeds: # features/step_definitions/feed_steps.rb:1 | url | | url 1 | | url 2 | | url 3 | | url 4 | http://www.example.com/feeds When I delete the 3rd feed # features/step_definitions/feed_steps.rb:5 Then I should see the following feeds: # features/step_definitions/feed_steps.rb:13 | Url | | url 1 | | url 2 | | url 4 | 1 scenario (1 passed) 3 steps (3 passed) 0m14.669s
どうでしょううまく通りましたでしょうか?実行エラーはSporkサーバのプロセスの方に吐き出されますので注意してください。これはテストコードがテストを実行しているインタプリタではなくSporkサーバに移譲されているためです。
テストの解説
テストの内容について少し解説します。features/manage_feeds.featureを覗いてみましょう。
このファイルはrake script/generate featureによって自動作成されました。"5つのurlが与えられていて、url='3'のレコードを削除したとき、その他のレコードが残っている"というシナリオです。
Givenのステップで| Url x |として与えられている値はfeatures/feed_steps.rbに配列として渡されレコードがインサートされます。
Given /^the following feeds:$/ do |feeds| Feed.create!(feeds.hashes) end
Then句でも||内の値は同様に配列として渡され、htmlの出力結果と異なることを試験します。
Then /^I should see the following feeds:$/ do |expected_feeds_table| expected_feeds_table.diff!(tableish('table tr', 'td,th')) end
さあ、これで一応cucumberが動くようになりました。GherkinやWhen-Then-Givenの書き方、ヘルパーメソッドなどに集中できる環境が整いました。次回以降また触れたいと思います。
.