开发者

Trouble testing controller using rspec and stubs

I have a hard time testing my controller with before_filters, exceptions and some mocking and stubing. Here is the controller:

before_filter :get_subject, :only => [:show, :edit, :update, :destroy, :update_field]
before_filter :user_has_to_belongs_to_subject_company, :only => [:show, :edit, :update, :destroy, :update_field]

def show
  @me开发者_如何转开发ssages = @subject.get_user_messages(current_user)
end

private

def get_subject
  @subject = Subject.find(params[:id])
end

def user_has_to_belongs_to_subject_company
  unless @current_user.company.eql?(@subject.company)
    raise "Error: current_user does not belongs to subject's company"
  end
end

And here is my spec file:

require 'spec_helper'

describe SubjectsController do  
  describe "for signed users" do
    before(:each) do
      @current_user = Factory(:user)
      sign_in @current_user
    end

    describe "for user belonging to subject's company" do
      before(:each) do
        @subject = mock_model(Subject)  
        Subject.stub!(:find).with(@subject).and_return(@subject)
        @current_user.stub_chain(:company, :eql?).and_return(true)
        @subject.stub!(:company)
      end

      it "should not raise an exception" do
        expect { get :show, :id => @subject }.to_not raise_error
      end
    end

    describe "for user not belonging to subject's company" do
      before(:each) do
        @subject = mock_model(Subject)  
        Subject.stub!(:find).with(@subject).and_return(@subject)
        @current_user.stub_chain(:company, :eql?).and_return(false)
        @subject.stub!(:company)
      end

      it "should raise an exception" do
        expect { get :show, :id => @subject }.to raise_error
      end
    end
  end
end

And finally, here is the error message:

SubjectsController for signed users for user belonging to subject's company should not raise an exception
     Failure/Error: expect { get :show, :id => @subject }.to_not raise_error
     expected no Exception, got #<RuntimeError: Error: current_user does not belongs to subject's company>
     # ./spec/controllers/subjects_controller_spec.rb:19:in `block (4 levels) in <top (required)>'

Thx for helping!


I'm not seeing the problem, but here's a refactoring suggestion. If you find yourself using more mocks and stubs that usual, maybe it's time to reconsider your interfaces. In this case, you can make your controller skinnier and you model fatter.

# subjects_controller_spec.rb
describe "for user belonging to subject's company" do
  before(:each) do
    @subject = mock_model(Subject, :verify_user => true)  
    Subject.stub!(:find).with(@subject).and_return(@subject)
  end

# subjects_controller.b
def user_has_to_belongs_to_subject_company
  @subject.verify_user(@current_user)
end

# subject.rb
class Subject
  def verify_user(user)
    unless user.company.eql?(company)
      raise "Error: current_user does not belongs to subject's company"
    end


What happens if you delete the @ in front of @current_user in

def user_has_to_belongs_to_subject_company
  unless @current_user.company.eql?(@subject.company)

to get

def user_has_to_belongs_to_subject_company
  unless current_user.company.eql?(@subject.company)

And in your specs, do controller.stub!(:current_user).and_return @current_user

I think the problem is one of scope - @current_user in your tests is different to @current_user in your controller. Really depends on how "sign_in @current_user" is implemented.

Also, instead of raising an exception, perhaps your before_filter could redirect the user to another page and set flash[:error]? The before filter is the right place to handle this situation, so it shouldn't raise an exception that would have to be rescued somewhere else (or if not, it would display a 500 page to the user).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜