Can't get this Rspec test to pass

Can’t get this Rspec test to pass

Hello,
I’m completely new to Rspec testing and I’m finding it very difficult to mock specific objects.

In this test, I have a before block setup as such:


  before do
    setup_controller_for_warden
    controller.session[:operation_id] = 1
    @operator = Factory :operator
    sign_in :operator, @operator

    @persist_herd = Herd.new
    @persist_herd.operation_id = 1;
    @persist_herd.herd_name = 'Persisted Herd (herd_rations_controller_spec)'
    @persist_herd.save!
  end

  describe "GET new" do
    it "assigns a new herd_ration as @herd_ration" do
      HerdRation.stub(:new){ mock_herd_ration }
      Herd.stub(:find).with(1) { @persistant_herd }

      get :new, :herd_id => 1
      assigns(:herd_ration).should be(mock_herd_ration)
      response.should be_success
    end
  end


and here's my controller method:

  def new
    @herd_ration = HerdRation.new
    @herd = Herd.find(params[:herd_id])

    if @herd
      respond_with(@herd_rations, :layout=> !request.xhr?)
    else
      redirect_to(root_url, :notice => 'No herd selected for ration.')
    end
  end

Here’s the catch - we have this groovy little plugin that globally enforces a model scope via a session id, in this case: session[:operation_id].

Here’s the code for the plugin:


module ApplicationScopeManager


   mattr_accessor :global_scope
   @@global_scope = []

   mattr_accessor :local_scope
   @@local_scope = {}

   def self.included(base)
      base.send :extend, ClassMethods
   end

   def self.setup
      yield self
   end

   module ClassMethods


      def method_missing(name, *args, &block)

         return acts_as_scope_manager($1, args) if name.to_s =~ /^acts_as_scope_manager_for_(.*)/

         return honors_scope_of($1, args) if name.to_s =~ /^honors_scope_of_(.*)/

         return current_scope_for($1) if name.to_s =~ /^current_scope_for_(.*)/

         super
      end

      def current_scope_for(scope)
         Thread.current[scope.to_sym]
      end

      def acts_as_scope_manager(scope, *args)
         options = args[0].extract_options! if args
         send :include, InstanceMethods

         set_global_scope(scope,options[:with_global_scope]) if options[:with_global_scope]

         send :before_filter, "set_scope_for_#{scope}".to_sym if self.ancestors.include? ActionController::Base
         send :default_scope, where(scope.to_sym => send("current_scope_for_#{scope}".to_sym)[:finder_scope]).create_with(scope.to_sym =>
         send("current_scope_for_#{scope}".to_sym)[:creator_scope]) if (self.ancestors.include? ActiveRecord::Base) && Thread.current[scope.to_sym]
      end

      alias honors_scope_of acts_as_scope_manager

      private


      def set_global_scope(scope, *args)
         Thread.current[scope.to_sym] = {:global_scope => args}
      end

   end

   module InstanceMethods

      def method_missing(name, *args, &block)

         return set_scope_for($1, args) if name.to_s =~ /^set_scope_for_(.*)/

         super
      end

      private

      def set_scope_for(scope, *args)
         if session[scope].class == Array
            application_scope = {:finder_scope => session[scope], :creator_scope => nil }
         else
            application_scope = {:finder_scope => [session[scope]], :creator_scope => session[scope] }
         end

         application_scope[:finder_scope] = application_scope[:finder_scope] + Thread.current[scope.to_sym][:global_scope] if Thread.current[scope.to_sym][:global_scope]

         Thread.current[scope.to_sym] = application_scope

      end

   end
end


This plugin enforces any model that calls the honors_scope_of_operation_id to include a lookup of the session[:operation_id] in all database calls. For instance if I do a Model.find(params[:id]) it will automatically add a WHERE “field_name”.“operation_id” = to the where clause. The problem I’m having is that I can’t seem to mock the session[:operation_id] in my Rspec tests. I thought setting it this way controller.session[:operation_id] = 1 in the before block would have been sufficient.

Any ideas?

Hello, I found a solution that makes this test pass and it was simply to mock out the controller’s find method as such:

Herd.stub(:find).with(@persist_herd.id) { mock_herd }

I am probably not fully understanding RSpec but this feels strange to me. In my understanding of writing tests, you want to first prepare the test environment by creating the proper database/objects relevant to the testing environment, pass the relevant parameters and test the results of method you are testing. Mocking out this controller code

 @herd = Herd.find(params[:herd_id]) 

with this

Herd.stub(:find).with(@persist_herd.id) { mock_herd } 

doesn’t seem to let the controller test it’s own code? Why can’t the parameters I’m passing to the controller be enough to test

 Herd.find(params[:herd_id]) ? 

Please help me understand this?

Hello, I found a solution that makes this test pass and it was simply to mock out the controller’s find method as such:

Herd.stub(:find).with(@persist_herd.id) { mock_herd }

I am probably not fully understanding RSpec but this feels strange to me. In my understanding of writing tests, you want to first prepare the test environment by creating the proper database/objects relevant to the testing environment, pass the relevant parameters and test the results of method you are testing. Mocking out this controller code

 @herd = Herd.find(params[:herd_id]) 

with this

Herd.stub(:find).with(@persist_herd.id) { mock_herd } 

doesn’t seem to let the controller test it’s own code? Why can’t the parameters I’m passing to the controller be enough to test this:

 Herd.find(params[:herd_id]) 

Please help me understand this?