使用 rspec 和存根测试控制器时出现问题

发布于 2024-11-15 22:37:50 字数 2157 浏览 2 评论 0原文

我很难使用 before_filters、异常以及一些模拟和存根来测试我的控制器。 这是控制器:

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

这是我的规范文件:

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

最后,这是错误消息:

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)>'

谢谢帮助!

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
  @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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

空城缀染半城烟沙 2024-11-22 22:37:50

我没有看到问题,但这里有一个重构建议。如果您发现自己比平常使用更多的模拟和存根,也许是时候重新考虑您的接口了。在这种情况下,您可以使控制器更瘦,模型更胖。

# 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

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
丶视觉 2024-11-22 22:37:50

如果您删除 @current_user 前面的 @

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

来获取

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

会发生什么并且在您的规范中,执行controller.stub!(:current_user).and_return @current_user

我认为问题是范围之一 - 您测试中的 @current_user 与@current_user 在你的控制器中。真正取决于“sign_in @current_user”的实现方式。

另外,也许您的 before_filter 可以将用户重定向到另一个页面并设置 flash[:error],而不是引发异常? before 过滤器是处理这种情况的正确位置,因此它不应该引发必须在其他地方救援的异常(或者如果没有,它会向用户显示 500 页)。

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).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文