0

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.

2 Answers 2

2

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
Sign up to request clarification or add additional context in comments.

2 Comments

Unfortunatly rspec-rails is currently lagging behind the state of the art and the documentation does not really mirror the shift in testing methodology that came with Rails 5. Controller specs are on the way out though as they rely on components that may get yanked in the near future.
I did think I was probably approaching it wrong in the first place - it didn't occur to me to perform the tests in the model itself. I've used assigns for now which works, however will structure this as you've suggested in the future. Thanks for the help.
0

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.

3 Comments

Thanks for the answer - I've not used the rails-controller-testing gem so am just reading up on what it can offer now.
@Mark, rails-controller-testing was previously part of rails. In rails 5 it got removed (as per the described reason).
Don't use rails-controller-testing for a new project. Instead go with a future proof testing strategy. everydayrails.com/2016/08/29/…

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.