2012-02-21 21 views
2

Rspecの新機能で、コードベースをRails 3.0.xからRails 3.1.xに移行し、同時にテストを追加しています。私は基本的なコントローラーテストを実行することができましたが、Deviseの統合を開始した後、問題にぶつかり始めました。具体的には、に属するUserというDeviseオブジェクトがあり、Companyには多くのCommunitiesがあります。コントローラCommunitiesのテストを記述しようとしていますが、アソシエーション(たとえばcontroller.current_user.communities)で参照しようとすると、作成したFactoryオブジェクトを参照できません。私は、次の(または類似の)エラーを取得をテストしようとすると:Rspec + Devise + Factory Girl Testing with Associations

No route matches {:id=>nil, :controller=>"communities", :action=>"edit"}

私はRSpecの/ Factory_Girlへの基本的な関連何かが欠けていると確信しているが、任意の助けもいただければ幸いです。次のように


Communitiesためedit作用を試験するためのセットアップの一例は次のとおり

/config/routes.rb

Units::Application.routes.draw do 

    devise_for :users 

    resources :companies 
    resources :communities 

    ... 

    root :to => 'companies#index' 

end 

/app/models/user.rb

class User < ActiveRecord::Base 
    belongs_to :company 
    has_many :communities, :through => :company 
    ... 
end 

/app/models/company.rb

class Company < ActiveRecord::Base 
    has_many :users 
    has_many :communities 
    ... 
end 

/app/models/community.rb

class Community < ActiveRecord::Base 
    belongs_to :company 
    ... 
end 

/spec/controllers/communities_controller_spec.rb

require 'spec_helper' 

describe CommunitiesController do 
    render_views 
    login_user 
    ... 
    context "GET #edit" do 
    before(:each) do 
     @company = controller.current_user.company 
     @community = controller.current_user.communities.new[Factory.build(:community, :company => @company)] 
     controller.current_user.company.communities.should_receive(:find).with(:company => @company) 
    end 

    it "should be successful" do 
     get :edit, :id => @community 
     response.should be_successful 
    end 

    it "should find a specific community" do 
     get :edit, :id => @community 
     assigns(:community).should eq(@community) 
    end 
    end 
    ... 
end 

/app/controllers/communities_controller.rb

class CommunitiesController < ApplicationController 
    ... 
    def edit 
    @community = current_user.communities.find(params[:id]) 
    end 
    ... 
end 

/spec/support/controller_macros.rb

module ControllerMacros 
    def login_user 
    before(:each) do 
     @request.env["devise.mapping"] = Devise.mappings[:user] 
     company = Factory.create(:company) 
     user = Factory.create(:user, :company => company) 
     # user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the confirmable module 
     sign_in user 
    end 
    end 
end 
+1

'config/routes.rb'を追加してください。 – lucapette

+1

' 'それは成功するはずです' 'セクションに' p @ community'を追加して、結果を教えてください。 – farnoy

+0

@farnoy私は 'p @ community'をそのセクションに入れましたが、出力を変更しませんでした。私はまだ次のエラーが発生しています: 'Failure/Error:get:edit、:id => @community ActionController :: RoutingError: ルートが一致しません。{:id => nil、:controller = 、:action => "edit"} ' – theandym

答えて

3

エラー: "Noルート一致{:ID =>ゼロ、:コントローラ=>" コミュニティ ":アクション=> "編集"}" あなたの前の行(の結果である:各々が)ブロックは次のようになります。

@community = controller.current_user.communities.new[Factory.build(:community, :company => @company)] 

Factory.buildはFactory.createとは異なります。 Buildはオブジェクトの新しいインスタンスを作成しますが、実際にはデータベースに保存しません。さらに、新しいFactoryインスタンスを保存せずに新しいCommunityインスタンスを作成しています。コミュニティではないので

get :edit, :id => @community 

:あなたはこの後@community変数を取って、「取得」メソッドに、あなたのテストでそれを渡している

@community = Factory.create(:community, :company => @company) 

:私は次のようにコミュニティを作成することをお勧め保存されていてもIDはありません。それはメモリ内にのみ存在します。さらに、(Factory.buildをFactoryを読み込むように更新した後で)@communityオブジェクトのidを取得する方が正しいでしょう。)を作成:

get :edit, :id => @community.id 

第二に、あなたの協会がライン上であなたのコントローラ内のロジックと一致するように表示されません:あなたのコントローラで

controller.current_user.company.communities.should_receive(:find).with(:company => @company) 

、あなたはCURRENT_USERて連鎖することで、コミュニティを見つけています。コミュニティではなく、current_user.company.comコミュニティです。実装ではなく、結果をテストしたいので、このテストを削除することをお勧めします。これはテストをコード変更に脆弱にします。

最後に、テストで複数のアサーションがあることをお伝えしたいと思います。あなたは、あなたの前に主張している(各):

controller.current_user.company.communities.should_receive(:find).with(:company => @company) 

各テストは二つの条件をチェックされるように、これは、その下にネストされた試験のそれぞれで実行されているが。これはよりよく分離されるべきです。

it "should find communities" do 
    controller.current_user.company.communities.should_receive(:find).with(:company => @company) 
end 

私は上記の言及のように、それはあまりにもあるしかし、私はこのテストは素晴らしいアイデアだとは思わない:私は、独自のテストブロックにこのコードを移動し、メソッドの前からそれを動かす提案しますあなたがテストしているものの実装と密接に結びついています。

+0

わかりやすい説明をいただきありがとうございます。また、出力ではなく実装のテストを避けることも良い考えです。私はそれに応じて自分のコードを変更しました。 – theandym

関連する問題