Today I’ve been writing tests for a legacy Rails application I inherited recently. The application has several user roles, each role having varying permissions. To deal with this nicely I setup shoulda macro’s to create contexts for each of the user roles, public user, standard user, admin user etc. then in my tests I could write…
public_context do
context "on GET to :index" do
setup do
get :index
end
should_redirect_to("root url") { root_url }
end
end
signed_in_user_context do
context "on GET to :index" do
setup do
get :index
end
should_redirect_to("user url") { user_url }
end
end
This is pretty standard practice now and something I picked up from looking at the code produced by the guys at Thought Bot. While working on the test suite it became apparent many of the methods behaved in the same way for multiple user roles. I wanted to come up with a way to run a group of tests under multiple user roles without having to duplicate any code. Shoulda macros to the rescue again! After creating another macro to deal with multiple contexts I can write my tests like this…
multiple_contexts ['public_context', 'signed_in_user_context'] do
context "on GET to :show" do
setup do
@advert = Factory(:advert)
get :show, :id => @advert.to_param
end
should_render_with_layout :application
should_render_template :show
should_not_set_the_flash
should_assign_to( :advert ) { @advert }
should_respond_with :success
end
end
And the shoulda macro code itself…
def multiple_contexts(contexts, &blk)
contexts.each { |context|
send(context, &blk) if respond_to?(context)
}
end
def public_context(&blk)
context "The public" do
setup { sign_out }
merge_block(&blk)
end
end
def signed_in_user_context(&blk)
context "A signed in user" do
setup do
@user = Factory(:user)
sign_in_as @user
end
merge_block(&blk)
end
end