簡體   English   中英

帶有FactoryGirl和實例變量的Rails rspec

[英]Rails rspec with FactoryGirl and instance variables

我編寫的測試不是很好,並且在將Application Controller中的實例變量用於測試中的其他控制器時遇到了一些麻煩。 在Rails中,我有一個非常簡單的控制器動作。

  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)>'

請幫忙,我應該怎么做才能將這樣的實例變量組合起來並建立關聯呢?

您必須正確設置測試用例中使用的所有關聯,以防丟失分配了城市的國家(因此稱為nil.cities),或像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

如果您知道自己正在采取什么措施來防止觸及數據庫(慢!),那么模擬可能會非常有用,因為AR已經經過了很好的測試。 盡管實現中存在錯誤,但也可以讓您編寫通過測試,因此請明智地使用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM