I have the following ActiveRecord classes:
class User < ActiveRecord::Base cattr_accessor :current_user has_many :batch_records end class BatchRecord < ActiveRecord::Base belongs_to :user named_scope :current_user, lambda { { :conditions => { :user_id => User.current_user && User.current_user.id } } } end
and I’m trying to test the named_scope :current_user using Shoulda but the following does not work.
class BatchRecordTest < ActiveSupport::TestCase setup do User.current_user = Factory(:user) end should_have_named_scope :current_user, :conditions => { :assigned_to_id => User.current_user } end
The reason it doesn’t work is because the call to User.current_user in the should_have_named_scope method is being evaluated when the class is being defined and I’m change the value of current_user afterwards in the setup block when running the test.
Here is what I did come up with to test this named_scope:
class BatchRecordTest < ActiveSupport::TestCase context 'with User.current_user set' do setup do mock_user = flexmock('user', :id => 1) flexmock(User).should_receive(:current_user).and_return(mock_user) end should_have_named_scope :current_user, :conditions => { :assigned_to_id => 1 } end end
So how would you test this using Shoulda?
I think you are going about this the wrong way. Firstly, why do you need to use a named scope? Wont this just do?
In which case it would be trivial to test. BUT! WTF are you defining
current_useras a class attribute? Now that Rails 2.2 is ‘threadsafe’ what would happen if you were running your app in two seperate threads? One user would login, setting thecurrent_userfor ALLUserinstances. Now another user with admin privileges logs in andcurrent_useris switched to their instance. When the first user goes to the next page he/she will have access to the other persons account with their admin privileges! Shock! Horror!What I reccomend doing in this case is to either making a new controller method
current_userwhich returns the current user’s User instance. You can also go one step further and create a wrapper model like:Oh, and by the way, now I look at your question again perhaps one of the reasons it isn’t working is that the lineEDIT I’m an idiot.User.current_user && User.current_user.idwill return a boolean, rather than the Integer you want it to.Named scope is really the absolutely wrong way of doing this. Named scope is meant to return collections, rather than individual records (which is another reason this fails). It is also making an unnecessary call the the DB resulting in a query that you don’t need.