Now we get down to brass tacks. In order to make my tests DRY (appropriately) and allow for all my controllers to test if someone is logged in and has access, I set up this shared context
spec/support/user_authentication.rb
123456
describe"an admin is logged in",:shared=>truedobefore(:each)docontroller.stubs(:login_required=>true)controller.stubs(:current_user=>Factory.build(:user,:login=>'admin',:roles_list=>["super"]))endend
From there, all we need to do is put it all together, setting up trackers parent @advertiser and the @tracker we’ll be using and stubbing the ActiveRecord find so that it always returns @advertiser
spec/controllers/trackers_controller.rb
123456789
describeTrackersControllerdoit_should_behave_like"an admin is logged in"integrate_viewsbefore(:each)do@advertiser=Factory.create(:advertiser)@tracker=@advertiser.trackers.create(Factory.attributes_for(:tracker))Advertiser.stubs(:find=>@advertiser)end
Now we simply specify the part of the path that is needed to find the nested route by using :advertiser_id => @advertiser
it"index action should render index template"doget:index,:advertiser_id=>@advertiserresponse.shouldrender_template(:index)endit"show action should render show template"doget:show,:advertiser_id=>@advertiser,:id=>@trackerresponse.shouldrender_template(:show)endit"new action should render new template"doget:new,:advertiser_id=>@advertiserresponse.shouldrender_template(:new)endit"create action should render new template when model is invalid"doTracker.any_instance.stubs(:valid?).returns(false)post:create,:advertiser_id=>@advertiserresponse.shouldrender_template(:new)endit"create action should redirect when model is valid"doTracker.any_instance.stubs(:valid?).returns(true)post:create,:advertiser_id=>@advertiserresponse.shouldredirect_to(advertiser_tracker_url(@advertiser,assigns[:tracker]))endit"edit action should render edit template"doget:edit,:advertiser_id=>@advertiser,:id=>@trackerresponse.shouldrender_template(:edit)endit"update action should render edit template when model is invalid"doTracker.any_instance.stubs(:valid?).returns(false)put:update,:advertiser_id=>@advertiser,:id=>@trackerresponse.shouldrender_template(:edit)endit"update action should redirect when model is valid"doTracker.any_instance.stubs(:valid?).returns(true)put:update,:advertiser_id=>@advertiser,:id=>@trackerresponse.shouldredirect_to(advertiser_tracker_url(@advertiser,assigns[:tracker]))endit"destroy action should destroy model and redirect to index action"dodelete:destroy,:advertiser_id=>@advertiser,:id=>@trackerresponse.shouldredirect_to(advertiser_trackers_url(@advertiser))Tracker.exists?(@tracker.id).shouldbe_falseendend
Works! And works great! A minimal and excellent way to test your controllers, especially for access. You can easily create additional shared contexts with different user permissions and extend out the tests to make sure users that don’t have access can properly access them.