为什么这个Ruby条件赋值没有被记忆?

时间:2014-05-17 10:41:27

标签: ruby rspec

有人可以解释为什么这个规范失败了吗?

RSpec结果:

User#presenter memoizes presenter
     Failure/Error: user.presenter
       (<UserPresenter (class)>).new(...)
           expected: 1 time with any arguments
           received: 2 times with arguments: (...)

根据我对条件赋值运算符的理解,它应该只分配@presenter一次。

 # app/models/user.rb
def User
    def presenter
        @presenter ||= UserPresenter.new(self)
    end
end 

# app/presenters/user_presenter.rb
class UserPresenter
end

# spec/models/user_spec.rb
describe User do

    let(:user){ build_stubbed(:user) }

    describe "#presenter" do
        it "memoizes presenter" do
            UserPresenter.should_receive(:new).once
            user.presenter
            user.presenter # should not call .new
        end
    end
end

1 个答案:

答案 0 :(得分:1)

问题是这一行:

UserPresenter.should_receive(:new).once

这段代码只是设置了UserPresenter一次接收new方法的期望。它会删除原始的UserPresenter#new方法,并将其替换为返回nil的方法。由于nil是假的,因此@presenter实例变量不会被记忆。

要解决此问题,您可以指定期望值的返回值:

UserPresenter.should_receive(:new).once.and_return "some truthy value"

或等效

UserPresenter.should_receive(:new).once { "some truthy value" }

或者如果您绝对想要调用原始方法

UserPresenter.should_receive(:new).once.and_call_original

或使用新的期望语法

expect(UserPresenter).to receive(:new).once.and_call_original

有关预期消息的详细信息,请参阅this;有关调用原始方法的详细信息,请参阅thisThis对RSpec的should_receive方法进行了进一步的讨论。