Cucumber + PHP
勉強のために github の Cucumber + PHP の設定方法に関するドキュメントを翻訳してみた。
PHP だけでなく Ruby 以外のどんな言語で作られたアプリケーションにも当てはまるので、よかったら参考にしてみてください。
原文:PHP - cucumber - GitHub
多くの人は rails をテストするために cucumber を使っているので、ウェブ上にあるハウツーやドキュメントのほとんども rails 向けに書かれている。しかし cucumber は素晴らしいツールなので、どんな種類のウェブアプリケーションでもテストできるし、それがどんな言語で作られていても構わない。Selenium を使えばよいハウツーが用意されていることも確かだが、遅いし設定方法がダサいので、役に立つのは javascript をテストする必要があるときぐらいだろう。BDD のストーリーを書き、cucumber で PHP のアプリをテストしたい場合にはどうすればよいだろう?
思ったよりやり方は簡単である。Webrat を使えば rails、selenium または mechanize のどれかを使ってウェブアプリケーションとやりとりすることができる。なのでやることと言えば webrat が mechanize を使うように設定するぐらいで、あとはほとんどすべてがほかの cucumber のセットアップと同じ。
どうやればいいかはこんな感じ:
シナリオ: cucumber をインストールする 前提 Ubuntu を使用していること かつ まだ cucumber をインストールしていないこと もし "apt-get install ruby ruby1.8-dev rdoc1.8 irb libxml2-dev libxslt1-dev libc6-dev-i386 libopenssl-ruby"を実行する # apt を使うと妙なパスにインストールしてしまうので、手動で rubygems をインストールする かつ "wget http://rubyforge.org/frs/download.php/60718/rubygems-1.3.5.tgz"を実行する かつ "tar xvf rubygems-1.3.5.tgz"を実行する かつ "cd rubygems-1.3.5"を実行する かつ "sudo ruby setup.rb"を実行する # github を gem のソースリストに加える かつ "gem sources -a http://gems.github.com"を実行する かつ "sudo gem install cucumber mechanize rspec webrat"を実行する ならば cucumber のインストールが完了していること シナリオ: PHP アプリ向けに cucumber の環境を設定する 前提 動いている PHP アプリが存在すること かつ 現在位置がそのアプリのトップレベルのディレクトリであること もし "features"ディレクトリを作成する かつ "features/support"ディレクトリを作成する かつ "features/step_definitions"ディレクトリを作成する かつ 以下の行を"support/env.rb"に書く # RSpec require 'spec/expectations' # Webrat require 'webrat' require 'test/unit/assertions' World(Test::Unit::Assertions) Webrat.configure do |config| config.mode = :mechanize end World do session = Webrat::Session.new session.extend(Webrat::Methods) session.extend(Webrat::Matchers) session end ならば cucumber のテストを書き実行できること
その他いくつか気付いた点:
webrat は mechanize 使うように設定すると response.body の代わりに response_body を使うようだ。どうしてそうなのかはよくわからないが、http://github.com/brynary/webrat にある webrat のステップ定義を使う場合には、いくつかの置換をしないとうまく動かなかった。
もしテストのたびに同じテストデータを使いたいなら、いくつかの必須要件がある。まず、(テスト用の)データベースを用意してデータ内容を把握し十分にコントロールできるようにする必要がある。それから、テストを繰り返し実行するために、毎回同じデータを用意するべきだということである。*1
これを解決するためには、ちょっとハックしてシナリオの前と後に、データベースとテーブルのダンプを行えばよい。一番最初のテストを行う前にデータベースの状態を保存しておいて、最後に再読み込みし、次にテストを実行したときにもデータベースの中身は同じにするか、あるいは上記と同じことをフィーチャ毎・テーブル毎に繰り返すか。今まで試してきた中では、2 番目のアプローチのほうが速くて柔軟性もあるように思えた。
フィーチャ毎・テーブル毎のアプローチは hooks を使うと実現できる。以下に挙げるのは私が 'support/hooks.rb' の中に書いてあるコードである。
Before ('@reset_users') do # Save user table data save_table("game_user") end After ('@reset_users') do # Reload user table data load_table("game_user") end def save_table(table_name) run "mysqldump -u #{@@test_database_username} --password=#{@@test_database_password} #{@@test_database_name} #{table_name}> /tmp/#{table_name}" end def load_table(table_name) run "mysql -u #{@@test_database_username} --password=#{@@test_database_password} #{@@test_database_name} < /tmp/#{table_name}" end
あとは @reset_users タグを user テーブルで何かするシナリオの前に書くだけ。そうすればシナリオが完了したあとに user テーブルをリセットしてくれるだろう。
@reset_users Scenario: Create a user Given ...
PHP 向けの完全な env.rb はここにある。また、chits の features ディレクトリを見れば、実際にどうやって PHP アプリを cucumber でテストしているか見られるだろう。
*1:ここらへん原文のままだと少しわかりづらかったので意訳した