Search code examples
ruby-on-railsruby-on-rails-3testingrspecapplicationcontroller

Populate Instance Variable Defined In Parent Controller For Rspec Test


In my ApplicationController, I expose a variable that can be shared by all controllers:

before_filter :expose_group

protected

    # Much simplified
    def expose_group
      @user_group = LearningGroup.find_by_uid(cookies[:user_group])
    end

I'm testing my controllers using RSpec, and for some of these tests, I need to be able to set the @user_group to a known value before they are run. How can I set this variable when testing a subclass of ApplicationController?

Note: I need a way to set @user_group for the test. Controlling the return value of expose_group using a stub doesn't help as @user_group will still be nil.


Solution

  • I would scrap the instance variable altogether and use helpers instead. Start with something like a GroupsHelper in app/helpers/groups_helper.rb.

    module GroupsHelper
      def user_group
        @user_group ||= group_from_cookie
      end
    
      def user_group=(group)
        @user_group = group
      end
    
      private
    
      def group_from_cookie
        group_uid = cookies[:user_group]
        LearningGroup.find_by_uid group_uid unless group_uid.nil?
      end
    end
    

    Then include it in ApplicationController.

    class ApplicationController < ActionController::Base
      include GroupsHelper
      # ...
    end
    

    Now, in spec/support define a helper for your test.

    include ApplicationHelper
    
    def join_group group_uid
      # whatever preparation you may need to do as well
      cookies[:user_group] = group_uid
    end
    

    A test could look something like:

    it 'does something awesome' do
      join_group 'my awesome group id'
      # ...
      expect(your_subject).to be_awesome
    end
    

    When you run your test, user_group will return the value determined by the value you already assigned to the cookie object.

    This also has the benefit of just calling join_group rather than stubbing LearningGroup all over the place in multiple tests.