Authlogic, RSpec and :priority_record=>nil... wtf.
I think Authlogic is great. I think RSpec is great, but damn did I ever give myself a confusing error. My view specs were passing so I moved onto the controllers. The controller specs passed so I moved onto the models. After the models passed I tested all of the specs and found that I had broken the controllers some how.
When running my SessionsController tests I’d get an error like this:
<UserSession (class)> received :new with unexpected arguments expected: ({:password=>"valid password", :login=>"dane"})
got: ([{:priority_record=>nil}, nil])
At other times I’d get:
Mock "UserSession_1050" received unexpected message :priority_record= with (nil)
The only useful information I could find about this error was that other people had experienced it too. That’s the main reason for writing this post. So, rebuilding the specs and testing every step of the way I isolated the problem to the UserSession. All of the tests passed before I would test against the UserSession, which is an Authlogic model. I looked through the other controller specs and it was the same case. The tests passed until I started working with the UserSession, but only when the user was not logged in already. Interesting…
Here was my sessions_controller.rb_spec.rb file:
describe SessionsController, "POST create" do context "when the user is logged in already" do before(:each) do login_as_user post :create end it "should redirect the user to the dashboard" do response.should redirect_to dashboard_path end it "should have flash[:notice] defined" do flash[:notice].should == assigns[:logged_in_notice] end end context "when the user is not logged in" do context "when valid parameters are passed" do before(:each) do @user_session = mock_model(UserSession).as_new_record @user_session.stub!(:save!).and_return true UserSession.stub!(:new).and_return @user_session @post_user = { "login" => "dane", "password" => "my-password" } end it "should create a new session" do UserSession.should_receive(:new).with(@post_user) # the spec errored here post :create, :user => @post_user end # more tests followed end end end
That looks pretty straightforward.
I also have a spec_helpers/controller_helpers.rb file where I define login_as_user:
module ControllerHelpers def login_as_user # define user and session @current_user = mock_model(User, :login => "dane") @current_session = mock_model(UserSession) controller.stub!(:current_user).and_return @current_user controller.stub!(:current_session).and_return @current_session end end
If your code looks like this or something remotely close you’re in luck. The problem was caused by not stubbing out the current_user to return nil when the user was not logged in. I already had a login_as_user method, but I also needed to have a not_logged_in method.
I added the following to my spec_helpers/controller_helpers.rb file:
def not_logged_in controller.stub!(:current_user).and_return nil end
I also called not_logged_in method before each test that ran when the user was not logged in.
before(:each) { not_logged_in }
That fixed it, but what really caused it? With most user sessions you’ll have the methods current_user and current_session. Here is mine, it’s identical to the Authlogic example code.
def current_user return @current_user if defined?(@current_user) @current_user = current_session && current_session.record end def current_session return @current_session if defined?(@current_session) @current_session = UserSession.find end
You’ll see that calling current_user calls current_session and current_session calls UserSession. By stubbing current_user to return a mock user or nil avoids the current_session call and the UserSession call.
I hope this helps!
Comments
Comments have been closed.