33

Shouldn't I be able to see instance variables which are created in a controller action from within my rspect tests?

# /app/controllers/widget_controller.rb
...
def show
  @widget = ...
  puts "in controller: #{@widget}"
end
...

--

# /spec/controllers/widget_controller_spec.rb
RSpec.describe WidgetController, type: :controller do
...
describe "GET #show" do
  it "assigns the requested widget as @widget" do
    get :show, { :id => 1 } # this is just an example - I'm not hardcoding the id

    puts "in spec: #{@widget}"
  end
end
...

Here is the output I get when I run that spec:

controller: #<Widget:0x007f9d02aff090>
in spec:

Am I wrong in thinking that I should have access to @widget in my controller spec?

4 Answers 4

42

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[]

Sign up to request clarification or add additional context in comments.

1 Comment

RuboCop complains about the usage of local variables in tests. That being said controller.view_assigns['var_name'] works just fine without the @
24

#assigns is deprecated. Here's a solution that avoids pulling in the rails-controller-testing gem

Though it can be a code smell to test instance variables in controllers, to upgrade older apps you can leverage #instance_variable_get.

Rspec example: expect(@controller.instance_variable_get(:@person).id).to eq(person_id)

Comments

19

In Rails 5, assigns has now been split out into a new rails-controller-testing gem.

You can either install the gem to continue using assigns, or you could use what the rails-controller-testing gem uses internally, which@controller.view_assigns[].

1 Comment

@controller.view_assigns['widget']
0

In new Rails versions with rails-controller-testing gem you can access to instance variables two ways:

  • with assigns[:key] / assigns['key']

  • with controller.view_assigns['key']

As you see assigns is ActiveSupport::HashWithIndifferentAccess, so you you can use both a string or symbol as key. It is formed with regular_writer method from the Hash, where all the keys with instance variables are strings, i.e. from @controller.view_assigns. But you can also access to controller inside tests

Here example

require 'rails_helper'

describe SomeController, type: :controller do
  before do
    assign(:some_var, 10)

    get :show, params: { id: 1 }
  end

  it 'assigns the @some_var'
    expect(assigns['some_var']).to eq 10
    expect(assigns[:some_var]).to eq 10

    expect(controller.view_assigns['some_var']).to eq 10
  end
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.