Getting my spec on

Although I still consider myself a rookie in the RoR world, I recently made my way through the Rspec book, and came out of the experience with some new skills to sharpen. On an internal project at Redpoint, we’re again using CanCan for authorization and Authlogic for authentication. My first task after getting involved a second time around (I was involved before I learned Rspec/Cucumber/BDD, stopped, read the book, and now am back) was to back fill some test coverage.

Immediately, I ran into issues figuring out how much to test, when to test what, factories vs mocks, etc – all much discussed topics with typical purist and cool kid groups. After poring over a zillion resources via the normal sources (mostly google and stackoverflow), I decided the best way to sharpen those newly forged rspec skills was to dive in the purist way.

First, I made a quick decision to treat features tested via Cucumber as integration tests, and used models created with FactoryGirl to test them. Easy enough, I thought – the rest would be just as easy…

Well, not exactly.

After piecing together a solution from the blog and forum post’s of others (see links above). Here’s what I ended up with:

Authlogic – essentially, the strategy here is to override the methods normally put in ApplicationController.rb to create stub/mocks of UserSession and User models.

in spec_helper.rb:

require 'authlogic/test_case'

def current_user(stubs = {})
  @current_user = stub_model(User, {:login=>"a user name"}.merge(stubs))
end

def user_session(stubs = {}, user_stubs = {})
  @user_session ||= mock(UserSession, {:user => current_user(user_stubs), :record => true}.merge(stubs))
end

def login(session_stubs = {}, user_stubs = {})
  UserSession.stub!(:find).and_return(user_session(session_stubs, user_stubs))
end

def logout
  @user_session = nil
end

…resulting in tests that can call ‘login’ and ‘logout’ to simulate authenticated and unauthenticated users:

before { 
     login 
}

For CanCan, the solution came much quicker, and I think it was in a response to someone’s forum posting from Ryan Bates himself. In this case, we create an instance of ability, which is essential what is happening in the background during normal operation, and stack it with whatever :can’s we’d like. This new object just extends CanCan’s ability class, and we can alter it however we please. Now, my test contains something along these lines:

before { 
    login

    @ability = Object.new
    @ability.extend(CanCan::Ability)
    controller.stub(:current_ability).and_return(@ability) 
}

…and throughout my tests, when I want to set abilities, I add something like this where necessary:

     @ability.can :manage, :all

I hope this saves someone using the same Gems some time to see in one place. That is the only aspect of this post I can take credit for.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s