How to Test Instance Variable Was Instantiated in Controller with Rspec

Accessing controller instance variables from within an rspec controller spec

Use the assigns method (*note: assigns is now deprecated. See bottom of my answer for info):

it "assigns the @widget"
expect(assigns(:widget)).not_to be_nil
end

Of course, you can inspect widget as you'd like, but without seeing what @widget is from your provided controller code, I just checked if it was nil

If you're wanting to puts the widget, like in your example, just print it with assigns

puts assigns(:widget)

EDIT: assigns is now deprecated (see: https://apidock.com/rails/ActionController/TestProcess/assigns)

If you want to continue using assigns you will need to install the rails-controller-testing gem.

Otherwise, you could use what rails-controller-testing gem uses internally: @controller.view_assigns[]

How do I test an instance variable in a controller?

Your mentors are being stupid. While it can be good to understand controller specs as they are everywhere in legacy applications adding them to new applications is not a good practice.

For new Rails apps: we don't recommend adding the
rails-controller-testing gem to your application. The official
recommendation of the Rails team and the RSpec core team is to write
request specs instead. Request specs allow you to focus on a single
controller action, but unlike controller tests involve the router, the
middleware stack, and both rack requests and responses. This adds
realism to the test that you are writing, and helps avoid many of the
issues that are common in controller specs.

DHH explains pretty well what is wrong with testing the instance variables of your controller and what you should be doing instead:

Testing what instance variables are set by your controller is a bad
idea. That's grossly overstepping the boundaries of what the test
should know about. You can test what cookies are set, what HTTP code
is returned, how the view looks, or what mutations happened to the DB,
but testing the innards of the controller is just not a good idea.

Which is why assigns was extracted to a separate gem. It all boils down to testing what your code does - not how it does it.

See:

  • https://github.com/rspec/rspec-rails/issues/1838
  • https://github.com/rails/rails/issues/22496
  • https://github.com/rails/rails/issues/18950

RSpec - testing instance variables within a controller

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

@controller instance variable in Rspec

I believe this is actually being done by ActionController::TestCase::Behavior#setup_controller_request_and_response, which is wired up by RSpec::Rails::SetupAndTeardownAdapter#setup, which is included by RSpec::Rails::RailsExampleGroup and used by RSpec::Rails::ControllerExampleGroup. :)

bundle open rspec-rails is an easy way to start looking at how this stuff works.

HTH!



Related Topics



Leave a reply



Submit