简体   繁体   中英

RSpec - testing instance variables within a controller

I have a new action which creates a circle and assigns the current parent as its administrator:

def new
  return redirect_to(root_path) unless parent
  @circle = Circle.new(administrator: parent)
end

I'm trying to test that the administrator ID is properly set, and have written out my test as such:

context 'with a parent signed in' do
  before do
    sign_in parent
    allow(controller).to receive(:circle).and_return(circle)
    allow(Circle).to receive(:new).and_return(circle)
  end

  it 'builds a new circle with the current parent as administrator' do
    get :new
    expect(@circle.administrator).to equal(parent)
  end
end

This obviously throws an error as @circle is nil . How can I access the new object that hasn't yet been saved from my controller tests? I'm guessing it is some variety of allow / let but as I say all my searches have yielded nothing so far.

You're approaching the problem wrong. Test the behavior of the controller. Not its implementation.

If this is a legacy application you can use assigns to access the @circle instance variable of the controller:

context 'with a parent signed in' do
  before do
    sign_in parent
  end
  it 'builds a new circle with the current parent as administrator' do
    get :new
    expect(assigns(:circle).administrator).to equal(parent)
  end
end

But Rails 5 removes assigns and using it is not encouraged in new projects. Instead I would use a feature spec and actually test the steps of creating a circle:

require 'rails_helper'

RSpec.feature 'Circles' do

  let(:parent) { create(:parent) }

  context "a guest user" do
    scenario "can not create circles" do
      visit new_circle_path
      expect(page).to have_content 'Please sign in'
    end
  end

  context "when signed in" do
    background do
      login_as parent
    end

    scenario "can create circles" do
       visit new_circle_path
       fill_in 'name', with: 'Test Circle'
       expect do
         click_button 'Create circle'
       end.to change(parent.circles, :count).by(+1)
       expect(page).to have_content 'Test Circle'
    end 
  end
end

You can use assigns :

expect(assigns(:circle).administrator).to eq parent

However, note that with rails 5, this gets deprecated. The rational being that checking the assigned instance variables in controllers is too fragile and implementation specific.

The recommended alternative is either to test side effects (for example if this actually got persisted to the db) or do full feature tests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM