2012-02-21 173 views
2

我對Rspec很陌生,正在將代碼庫從Rails 3.0.x遷移到Rails 3.1.x並同時添加測試。我能夠獲得基本的控制器測試工作,但在開始整合Devise後,我開始遇到問題。具體來說,我有一個名爲User的Devise對象,屬於Company,而Company有很多Communities。我試圖爲Communities控制器編寫測試,當嘗試通過關聯引用(例如controller.current_user.communities)時,我無法引用我創建的Factory對象。當我嘗試測試,我得到以下(或類似)錯誤:Rspec + Devise +關聯工廠女孩測試

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

我敢肯定,我失去了一些東西基本涉及到Rspec的/ Factory_Girl,但任何幫助,將不勝感激。


設置用於測試edit行動Communities的一個例子是如下:

/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 2012-02-23 16:48:32

+1

你可以在'it'中添加'p @ community'應該是成功的''部分並給我們結果? – farnoy 2012-02-24 21:30:37

+0

@farnoy我在該部分放了'p @ community',但它沒有改變輸出。我仍然收到以下錯誤: '失敗/錯誤:get:edit,:id => @community ActionController :: RoutingError: 沒有路由匹配{:id => nil,:controller =>「communities」 ,:action =>「edit」}' – theandym 2012-02-26 03:03:11

回答

3

的錯誤: 「無路由匹配{:ID =>零,:控制器=>」 社區 「:動作=> 」編輯「}」 在你前行(的結果:每)塊的內容如下:

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

請注意,Factory.build與Factory.create不同。構建會創建該對象的新實例,但實際上並未將其保存到數據庫中。此外,您正在使用這個新的Factory實例創建一個新的社區實例,而不保存它。我建議創建社區如下:

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

你以後採取這一@community變量,並使其在測試的「get」方法:

get :edit, :id => @community 

因爲社區不是保存,它沒有ID。它只存在於內存中。此外,發送獲取@community對象的id(更新Factory.build以讀取Factory之後)會更加正確。創建):

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

其次,貴會不會出現與上線在你的控制器的邏輯是一致的:

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

在你的控制器,你是通過CURRENT_USER鏈接找到社區。社區,而不是current_user.company.communities。我建議刪除這個測試,因爲你想測試結果,而不是實現。這使測試過於脆弱,無法編碼更改。

最後,我想提一下,您在測試中有多個斷言。您聲稱在您的面前(:每個):

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 2012-02-27 05:51:27