2016-05-18 9 views
0

私はテストをあまりうまく書いていないので、テスト中の他のコントローラ用のApplication Controllerからのインスタンス変数を使っていくつか問題があります。 Railsではかなり単純なコントローラアクションがありました。このアクションのRails rspecでFactoryGirlとインスタンス変数

def index 
    @cities = City.all 
    @starred_cities = @cities.where(starred: true) 
    end 

私がテストしています。アプリケーションで

RSpec.describe CitiesController, :type => :controller do 
    let(:city) { create(:city) } 

    describe 'GET #index' do 
    let(:cities) { create_list(:city, 2) } 
    before { get :index } 

    it 'populates an array of all cities' do 
     expect(assigns(:cities)).to match_array(cities) 
    end 

    it 'renders index view' do 
     expect(response).to render_template :index 
    end 
    end 
end 

を私はドメイン名で国を取得し、すべてのコントローラにグローバルに設定する必要があります。私はこのようなApplicationControllerにするbefore_actionメソッドに追加します。

before_action :get_country 
def get_country 
    country_slugs = {en: 'usa', ru: 'russia', es: 'spain'} 
    current_country_slug = country_slugs[I18n.locale] 
    @country = Country.find_by_slug(current_country_slug) 
end 

そして今、私は、現在、国のために私のコントローラ内の都市を取得することができます:私のコントローラのテストが例外で失敗するので

def index 
    @cities = @country.cities 
    @starred_cities = @cities.where(starred: true) 
end 

は今、私はいくつかの問題があります:

Failures: 

1) CitiesController GET #index populates an array of all cities 
    Failure/Error: @cities = @country.cities 

    NoMethodError: 
    undefined method `cities' for nil:NilClass 
    # ./app/controllers/cities_controller.rb:5:in `index' 
    # ./spec/controllers/cities_controller_spec.rb:9:in `block (3 levels) in <top (required)>' 

2) CitiesController GET #index renders index view 
    Failure/Error: @cities = @country.cities 

    NoMethodError: 
    undefined method `cities' for nil:NilClass 
    # ./app/controllers/cities_controller.rb:5:in `index' 
    # ./spec/controllers/cities_controller_spec.rb:9:in `block (3 levels) in <top (required)>' 

このようなインスタンス変数を組み合わせて関連付けるにはどうすればよいですか?

+1

国の作成はどこですか?国がnilにデフォルト設定されているため例外が発生しています。 –

+0

'@ country'をどこで初期化していますか? – max

+0

@countryは 'before_action:get_country'から来ます。 – sixty4bit

答えて

0

テストケースで使用されているすべてのアソシエーションを適切に設定する必要があります。割り当てられた都市の国が見つからない(nil.citiesが呼び出される)か、ARが返すようにオブジェクトを返すメソッドをモックします。 :あなたはARは、すでに非常によくテストされているので(!遅い)デシベルを打つ防ぐために何をしているかを知っていれば

RSpec.describe CitiesController, :type => :controller do 
    describe '#index' do 
    let(:cities) { double('cities') } 
    let(:starred_cities) { double('starred_cities') } 
    let(:country) { double('country', cities: cities) } 

    before do 
     allow(cities).to receive(:where).with(starred: true).and_return(starred_cities) 
     allow(Country).to receive(:find_by_slug).and_return(country) 
     get :index 
    end 

    it 'populates an array of all cities' do 
     expect(assigns(:cities)).to match_array(cities) 
    end 

    it 'renders index view' do 
     expect(response).to render_template :index 
    end 
    end 
end 

モッキングは非常に役に立つことができます。しかし、実装にはバグがありますが、合格テストを書くこともできますので、それを賢明に使用してください。

+0

それが助けてくれることを願う – airled

関連する問題