简体   繁体   English

使用RSpec和存根的故障测试控制器

[英]Trouble testing controller using rspec and stubs

I have a hard time testing my controller with before_filters, exceptions and some mocking and stubing. 我很难通过before_filters,异常以及一些模拟和存根来测试我的控制器。 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
  @messages = @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 如果您删除了@current_user前面的@,会发生什么情况

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 在您的规范中,执行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. 我认为问题是范围之一-测试中的@current_user与控制器中的@current_user不同。 Really depends on how "sign_in @current_user" is implemented. 确实取决于“ sign_in @current_user”的实现方式。

Also, instead of raising an exception, perhaps your before_filter could redirect the user to another page and set flash[:error]? 另外,不是引发异常,也许您的before_filter可以将用户重定向到另一页并设置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). before过滤器是处理这种情况的正确位置,因此它不应引发必须在其他地方进行挽救的异常(否则,它将向用户显示500页)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM