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:
[code] 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 [/code]
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:
[code] 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
[/code]
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?