コントローラーの機能テストを作成しているときに、テストの 1 つが必要とするデータベースからの情報を要求する before_filter があるシナリオに出くわしました。Factory_girl を使用してテスト データを生成していますが、明示的に必要とされていないときにデータベースにアクセスすることは避けたいと考えています。また、ここで before_filter メソッドをテストすることも避けたいと思います (別のテストでテストする予定です)。私が理解しているように、モック/スタブはこれを達成する方法です。
私の質問は、このシナリオでこのメソッドをモック/スタブする最良の方法は何ですか。
私の before filter メソッドは、URL で見つかったサブドメインに基づいてデータベース内のサイトを探し、コントローラーで使用されるインスタンス変数を設定します。
#application_controller.rb
def load_site_from_subdomain
@site = Site.first(:conditions => { :subdomain => request.subdomain })
end
このメソッドを before_filter として使用するコントローラー:
# pages_controller.rb
before_filter :load_site_from_subdomain
def show
@page = @site.pages.find_by_id_or_slug(params[:id]).first
respond_to do |format|
format.html { render_themed_template }
format.xml { render :xml => @page }
end
end
ご覧のとおり、@site
(before_filter によって) 設定される変数に依存しています。@site
ただし、テスト中は、が設定されており、関連付けられたページが少なくとも 1 つある (によって検出された)ことをテストで想定したいと思います@site.pages
。load_site_from_subdomain
後でメソッドをテストしたいと思います。
これが私のテストで得たものです(ShouldaとMochaを使用):
context "a GET request to the #show action" do
setup do
@page = Factory(:page)
@site = Factory.build(:site)
# stub out the @page.site method so it doesn't go
# looking in the db for the site record, this is
# used in this test to add a subdomain to the URL
# when requesting the page
@page.stubs(:site).returns(@site)
# this is where I think I should stub the load_site_from_subdomain
# method, so the @site variable will still be set
# in the controller. I'm just not sure how to do that.
@controller.stubs(:load_site_from_subdomain).returns(@site)
@request.host = "#{ @page.site.subdomain }.example.com"
get :show, :id => @page.id
end
should assign_to(:site)
should assign_to(:page)
should respond_with(:success)
end
これにより、テスト結果にエラーが表示され、@site
nil であることがわかります。
私はこれについて間違った方法で進んでいるように感じます。サイトを単に Factory.create するだけでデータベースに存在するようにするのは簡単ですが、前述のように、テストを迅速に行うためにデータベースの使用を減らしたいと考えています。