RSpec功能测试中的Stub,Should_Receive和Before Block

时间:2012-11-02 04:02:20

标签: rspec functional-testing stub

下面的代码示例显示了RSpec Book中控制器规范章节中的重构:

require 'spec_helper'

describe MessagesController do
  describe "POST create" do
    it "creates a new message" do
      message = mock_model(Message).as_null_object
      Message.should_receive(:new).
        with("text" => "a quick brown fox").
        and_return(message)
      post :create, :message => { "text" => "a quick brown fox" }
    end

    it "saves the message" do
      message = mock_model(Message)
      Message.stub(:new).and_return(message)
      message.should_receive(:save)
      post :create
    end

    it "redirects to the Messages index" do
      post :create
      response.should redirect_to(:action => "index")
    end
  end
end

require 'spec_helper'

describe MessagesController do
  describe "POST create" do
    let(:message) { mock_model(Message).as_null_object }

    before do
      Message.stub(:new).and_return(message)
    end

    it "creates a new message" do
      Message.should_receive(:new).
        with("text" => "a quick brown fox").
        and_return(message)
      post :create, :message => { "text" => "a quick brown fox" }
    end

    it "saves the message" do
      message.should_receive(:save)
      post :create
    end

    it "redirects to the Messages index" do
      post :create
      response.should redirect_to(:action => "index")
    end
  end
end

我有几个问题:

1)我理解使用let块的好处,因为创建和保存的测试都使用mock_model。但是,我不明白前一块的好处。如果只有保存测试需要存根,那么为什么不将代码保留在测试中而不是将其移动到每次测试之前运行的before块?

2)更重要的是,before block是否会干扰创建测试指定的内容?创建测试说Message应该接收带有一些参数的new,然后使用post:create进行测试。但是如果前面的块只是将对new的调用断言,那么创建测试中的should_receive断言不会短路吗?也许我不理解stub和should_receive如何交互。

1 个答案:

答案 0 :(得分:0)

  

如果只有保存测试需要存根

典型的创建操作如下所示:

def create
  @message = Message.new(params[:message])
  if @message.save
    # ... etc. ...

所以是的,Message.new需要为每个例子加以存根。

  

如果前一个块只是将对new的调用断言,那么创建测试中的should_receive断言不会短路吗?

实际上它的工作原理相反。 before块首先运行并且存根:new,然后消息期望运行并替换存根。您可以删除before块并将存根放在其他两个示例的开头,并获得相同的效果。