Webアプリケーションでは、たくさんの項目を一覧表示する場合、1ページに全部見せるのではなくpaginate処理をして数ページに分ける場合があります。
たとえばGoogleの検索結果は通常、1ページに10件しか表示されません。
そういうページをRuby on Railsで作成する場合には、mislav-will_paginate pluginというプラグインを使用するということは割とよく知られていることです。
先日もそういうページを作成する必要があり、作成していましたが、RSpecでテストを作成しようとしたところやり方がわからず詰まりました。
そのため、その方法をここに記しておこうと思います。
ドキュメントを読もう!
実はGitHubのpluginのWikiページに最低限必要なことは書いてありました。
気がついていればもっと早く解決していたところでした。
「I’m getting “undefined method `total_pages’” error when rendering in the view!」という部分ですね。
ポイントはpaginateやtotal_pagesというメソッドをstub!で定義してあげることです。
実際のコード
- Controller: ArticlesController
- Model: Article
- title: string
- body: text
Controllerのテスト(の一部)
[$RAILS_ROOT/spec/controllers/articles_controller_spec.rb]
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe ArticlesController do describe "handling GET /articles" do before(:each) do article = mock_model(Article) article.stub!(:find).and_return([article]) @articles = [article] @articles.stub!(:total_pages).and_return(1) @articles.stub!(:paginate).and_return(@articles) end def do_get get(:index) end it "should be successful" do do_get response.should be_success end it "should render index template" do do_get response.should render_template('index') end it "should find all articles" do Article.should_receive(:paginate).with(:page => nil, :per_page => 100).and_return(@articles) do_get end it "should assign the found articles for the view" do do_get assigns[:articles].should == @articles end end end
ちなみに29行目の:page => nilになっているのは、たぶんassingsとかでparameterを指定していないからこうなるのだと思います。
まだshould_receiveをきちんと理解していないで、まともな説明が書けません。
Viewのテスト(の一部)
[$RAILS_ROOT/spec/views/articles/index.html.erb_spec.rb]
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') describe "/articles/index.html.erb" do include ArticlesHelper before(:each) do article_98 = mock_model(Article) article_98.stub!(:id).and_return(1) article_98.stub!(:title).and_return('MyString') article_98.stub!(:body).and_return('MyText') article_99 = mock_model(Article) article_99.stub!(:id).and_return(2) article_99.stub!(:title).and_return('MyString') article_99.stub!(:body).and_return('MyText') @articles = [article_98, article_99] @articles.stub!(:total_pages).and_return(1) @articles.stub!(:paginate).and_return(@articles) assigns[:articles] = @articles end it "should render list of articles" do render "/articles/index.html.erb" response.should have_tag("tr>td", "MyString", 2) response.should have_tag("tr>td", "MyText", 2) end end