【问题标题】:Stubbing Chained Methods with Rspec使用 Rspec 对链式方法进行存根
【发布时间】:2010-10-14 11:10:58
【问题描述】:

我想调用一个只返回一条记录的named_scope,但是named_scope返回一个数组,这没什么大不了的,因为我可以用.first链接它:

Model.named_scope(param).first

这行得通,我正在努力解决的是如何对链式调用进行存根。有人对我将如何通过 Rspec 模拟实现这一目标提供参考或答案吗?

【问题讨论】:

    标签: ruby-on-rails ruby rspec tdd bdd


    【解决方案1】:

    我想通了。

    Client.stub!(:named_scope).and_return(@clients = mock([Client]))
    @clients.stub!(:first).and_return(@client = mock(Client))
    

    这允许我调用我的控制器:

    @client = Client.named_scope(param).first
    

    有效,但有更好的解决方案吗?

    编辑:

    rspec 1.2.6 的发布允许我们使用 stub_chain 意味着它现在可以是:

    Client.stub_chain(:named_scope, :chained_call).and_return(@clients = [mock(Client)])
    

    这是我的头等大事,一如既往地检查 api 的细节 :)

    【讨论】:

    • 也许将 EDIT: 部分移到答案的顶部
    • 非常感谢,克里斯!它帮助了很多!
    【解决方案2】:

    更好的版本

    Client.stub!(:named_scope).and_return(@clients = mock([Client]))
    @clients.stub!(:first).and_return(@client = mock(Client))
    

    将是:

    Client.should_receive(:named_scope).with(param).and_return do
      record = mock_model(Comm)
      record.should_receive(:do_something_else)
      [record]  
    end
    

    【讨论】:

      【解决方案3】:

      这个问题已经很老了,因此在如何进行存根方面几乎没有改进。现在您可以使用 stub_chain 方法来存根方法调用链。 例如:

      @client = Client.named_scope(param).first

      可以被存根:

      Client.stub_chain(:named_scope,:first).and_return(@client = mock(Client))

      更多stub_chaining的例子:

      describe "stubbing a chain of methods" do
        subject { Object.new }
      
        context "given symbols representing methods" do
          it "returns the correct value" do
            subject.stub_chain(:one, :two, :three).and_return(:four)
            subject.one.two.three.should eq(:four)
          end
        end
      
        context "given a string of methods separated by dots" do
          it "returns the correct value" do
            subject.stub_chain("one.two.three").and_return(:four)
            subject.one.two.three.should eq(:four)
          end
        end
      end
      

      or please have a look at:

      rspecs 万岁!!! :)

      【讨论】:

        【解决方案4】:

        我想这是在控制器规范中?

        您自己的建议应该可以正常工作。另一种可能性是在模型中移动 named_scope 调用,以完全避免该问题。这也符合“胖模型,瘦控制器”的建议。

        【讨论】:

          【解决方案5】:

          我认为您已经通过将查询放入可以重用的命名范围来完成瘦控制器的工作。这是我开始使用命名范围之前使用的一些代码。

            def mock_comm(stubs={})
              @mock_comm ||= mock_model(Comm, stubs)
            end
          
            describe "responding to GET index" do
          
              it "should expose all comms as @comms" do
                Comm.should_receive(:find).with(:all).and_return([mock_comm])
                get :index
                assigns[:comms].should == [mock_comm]
              end
          # ...
          

          我可能会编写与您已经编写的代码非常相似的代码,但可能会将其放入一个允许我重用它的助手中。另一件事是使用不同的模拟框架,它可能会给你更多的控制权。看看 Ryan Bates 在 RSpec 上的 railscast - 现在有点老了,但仍然有一些好主意。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-12-25
            • 1970-01-01
            • 1970-01-01
            • 2015-08-31
            • 1970-01-01
            • 2012-05-19
            • 1970-01-01
            • 2016-01-02
            相关资源
            最近更新 更多