2016-05-18 71 views
0

我不写测试非常好,我有一些麻烦使用应用程序控制器的实例变量为另一个控制器在测试。 在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

创造一个国家在哪里?你正在得到例外,因为一个国家默认为零。 –

+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 

嘲讽可以说是相当有用的。但也可以让你编写通过测试,虽然你的实现有bug,所以明智地使用它。

+0

好的。希望它会有所帮助 – airled