RSpecを導入し始めたらrequireとか調べてた
(今日も作業ログ的日記的文章)
昨日に引き続きRSpecやってた。いよいよ今日はspecを書き始めた。
でもすぐにはまった。
経緯(というか全部をベタ書き)
前に作った勉強用アプリのspecを書き始めてみた。
(RSpecの本家サイトのドキュメントとかを参考にしながら書いていると、まずRails Tutorialで使っていたRSpecとのバージョンが違うことで、使い方が結構変わっていることに戸惑った。本題とは関係ないけど)
そのアプリでは、sentencesっていうリソースを以下のようにルート定義してるんだけど、
resources :sentences, only: [:index, :show, :edit, :update]
以下のspecのgetがうまく動かなくてはまった。
describe 'GET #show' do it 'renders the show template' do sentence1 = Sentence.create! get :show expect(response).to render_template('show') end end
答えは/setences/:id の:idを指定していないからで、今思えば当たり前に思える。
とにかくこのときは理由がわからなくて(get :index
は動いてたので)、get
のマニュアルを探した。
まず以下のrspec-railsのドキュメントに当たったんだけど、書いてない。そもそもあんまり網羅的に書いてある類のドキュメントじゃない。しかもなんでCSSが適用されてないみたいな見た目になってるんだろう。
File: README — Documentation by YARD 0.8.7.3
次に、Railsのメソッドかな?と思ってRailsのAPIを見たら、あった。
http://api.rubyonrails.org/classes/ActionController/TestCase/Behavior.html#method-i-get
ActionController::TestCase::Behavior#getメソッド。
でも本当にこのgetなのかいまいち確信が持てなくて、特定のメソッドがどのクラスに属するものなのか調べる方法はないのか、調べてみた。
ずばりな記事。
こういったケースでは、Kernel#methodとMethod#source_locationを組み合わせることで、メソッドの定義場所を見つけることができます。
なるほど。
つまり、specに
p method(:get).source_location
を書けばよさそう。
でもspecにこれを書いて標準出力で確認するのはなんかクールじゃないなと思って、rails consoleでできないだろうかと思った。
$ rails c Loading development environment (Rails 4.2.1) irb(main):001:0> require 'rails_helper' LoadError: cannot load such file -- rails_helper
だめ。これはまぁ想定通り。
irb(main):004:0> require './spec/rails_helper' LoadError: cannot load such file -- spec_helper
rails_helperは読めたけど、その中で読み込んでるspec_helperが読めない。spec_helperはパスじゃなく名前だけで指定されてるので、それも読み込むためにはrequireがファイルを探す仕組みを知らなければいけない。
調べたらすぐ出てきた。$LOAD_PATH
にディレクトリのリストが格納されていて、それを順にたどるらしい。なので、ここにspecディレクトリを追加してやればいい。
$LOAD_PATH == $:
のようなので、先頭に追加するには、
irb(main):010:0> $:.unshift(File.expand_path('./spec'))
これでいけた。requireできるだろうか。
irb(main):011:0> require 'rails_helper' NoMethodError: undefined method `configure' for RSpec:Module
なんか別のエラーが出た。そしてこれは根が深そう。RSpecの起動の仕組みを知らないと解決できなさそう。
というか、よく考えると、getの正体はすでにActionController::TestCase::Behavior#getではないかという予想はあって、その確信を得るために確認しようとしているんだけど、実際に使用している環境(spec)とは別の環境(rails console)で確認しても結局確信はできないような。
ということで大人しくspecの中にpを入れることにした。
p method(:get).source_location # => #<Method: RSpec::ExampleGroups::SentencesController::GETShow(ActionController::TestCase::Behavior)#get>
前半部分はRSpecによって自動的に作られているものだろうか。そこはよくわかってないものの、とりあえず括弧の中に疑惑のActionController::TestCase::Behaviorを発見。
やはりこいつだったということで、RailsのAPIを見たらget(action, *args)となってて、第二引数にパラメータのハッシュを渡す模様。そりゃそう。
ということで、こうしたらうまくいった。
get :show, id: 1
まとめ
頭悪くていろいろ大変。