Jpmobile on RSpec: RSpec で Rails プラグインを
概要
角谷さん と id:moro さんのるびま記事 http://jp.rubyist.net/magazine/?0021-Rspec を読んでいたら、JpmobileをRSpecベースにしたい熱が再燃。早速RSpecが使える環境を準備しました。
このとき、プラグインをRSpecでテストするためには色々と工夫が必要だったので、簡単にご紹介します(RSpecだから必要なのではありません。Test::Unitでも同種の工夫は必要でした)。
RSpecを実践で使うのは今回が初めてなので、誤っている点があるかもしれません。コメント等でご指摘いただければ幸いです。
なにが問題か
- Jpmobileプラグインは、Railsのフレームワーク(主にActionController以下)にメソッドを追加するため、これらが組み合わせた状態でテストされる必要があります。
- controller_name :xxx など、Rspec on Railsの機能を使いたいのです。しかし、RSpec on Railsは、「Railsアプリケーションの」 vendor/plugin 以下にインストールされることを前提にしています。
- ActionControllerのテストのためだけにRailsアプリケーションを用意するのは大袈裟なので、できれば避けたいところです。
ヒント
RSpec on Rails自体のspecが用意されており、これを検証するために必要になるrailsアプリケーション(もどき)が rspec_on_rails/spec_resources に存在しています。この rspec_on_rails/spec_resources を利用するための記述が rspec_on_rails/spec/spec_helper.rb に書かれおり、とても参考になります。以降、これを参考にしながらJpmobileをRSpec対応にしていきます。
ディレクトリ構造
ディレクトリ構造はRSpec on Railsに合わせておくことにしました。プラグインのrootからみて以下のように配置しました。
- spec/
- spec用ディレクトリ
- spec/controller/
- 以下に(controller用の)specを配置。
- spec/spec_helper.rb
- ヘルパー
- spec/spec.opts
- RSpecのオプションを指定するファイル
- spec_resources/controller/application.rb
- ApplicationController。RSpec on Railsが読み込まれるとすぐに require 'application' が実行されるので、このファイルは必要です。
- spec_resources/controller/
- 以下に検証用コントローラ
ラ
- vendor/plugin/rspec
- RSpec配布物(10/4追記: RSpecがインストールされていない環境で、プラグインをインストールしたrailsアプリケーションのrakeが動かなくなる問題がありましたので、こちらも同梱することにしました。)
- vendor/plugin/rspec_on_rails
- RSpec on Rails配布物
肝: spec_helper.rb
Jpmobileのspec/spec_helper.rb (r113)をご覧ください。
処理の大まかな流れは以下のようになります。
- % spec spec として実行すると、spec_helper.rbが二回requireされてしまいます(原因調査中)。これを防ぎます。
- action_controllerを読み込みます。
- Jpmobile本体を読み込みます。
- RAILS_ROOTをプラグインのrootにしておきます。RSpec on Railsの中でRAILS_ROOTを参照している部分があるので、指定しておかないとエラーが出ます。
- RSpec on Railsのディレクトリを$LOAD_PATH、load_paths、load_once_pathsの先頭に追加します。
- RSpec on Railsを読み込みます。
- (2007/10/4追記) routes を追加します。これが無いと get :index などが No route matches となって失敗します。
- spec_resources にあるコントローラ群が読み込まれるよう、$LOAD_PATH、load_paths、load_once_pathsの先頭に追加します。
- RSpec on Railsを呼びます。
さらに: Rakefile
Rakefileでrspec_on_rails/tasks/rspec.rakeを読み込んでおきます。
RAILS_ROOT = '.'
load 'vendor/plugins/rspec_on_rails/tasks/rspec.rake'
これで rake spec が通るようになります。
ハマりどころ
% spec spec/controller/hoge_spec.rb
などとすると、ディレクトリ名によって自動判断されてControllerBehaviourHelpersが読み込まれる(describeの中でcontroller_name :xxxなどが使える)のですが、spec/controllerディレクトリに入って
% spec hoge_spec.rb
とすると、そのままではControllerBehaviourHelpersが読み込まれません。これは
describe "DoCoMo SH902i からのアクセス", :behaviour_type=>:controller do
と、:behaviour_typeを明示する事で解決できるようです。
課題
まだView関連のspecは書いていませんが、同じようなやり方でできそうな雰囲気です。問題はTest::Unitからどうやって移行するかと、そもそも綺麗なspecをどう書くかという部分でしょうか。
追伸
RSpec+Autotest::Screen は気持ちよすぎます。