3

コントローラーの機能テストを作成しているときに、テストの 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.pagesload_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

これにより、テスト結果にエラーが表示され、@sitenil であることがわかります。

私はこれについて間違った方法で進んでいるように感じます。サイトを単に Factory.create するだけでデータベースに存在するようにするのは簡単ですが、前述のように、テストを迅速に行うためにデータベースの使用を減らしたいと考えています。

4

2 に答える 2

1

「Site.first」をスタブアウトしてみてください。これは、スタブする必要がある @site 変数の設定であり、before_filter から返された変数ではないためです。

于 2010-10-04T21:34:39.590 に答える
0

あなたの理由@sitenil、あなたload_site_from_subdomainが値の割り当てを行うためです@site- それは値を返さないため、あなたのスタブはload_site_from_subdomain単に に値を割り当てません@site。これには 2 つの回避策があります。

最初の方法:

load_site_from_subdomain戻り値だけを行うように変更します。

def load_site_from_subdomain
  Site.first(:conditions => { :subdomain => request.subdomain })
end

次に、を削除して次のようbefore_filter :load_site_from_subdomainに変更showします。

def show
  @site = load_site_from_subdomain
  @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

次に、テストでスタブを実行します。

@controller.stubs(:load_site_from_subdomain).returns(@site)

@siteを介して間接的にスタブされることを保証しますload_site_from_subdomain

第二の方法

をスタブするSite.firstには、機能テストの場合と同様に、このアプローチはあまり好きではありません。モデルがどのように取得されるかはあまり気にしませんが、respond. とにかく、このパスに進みたい場合は、テストでスタブすることができます:

Site.stubs(:first).returns(@site)
于 2012-10-24T22:44:04.490 に答える