【问题标题】:RSpec "let" method incorrectly returns nilRSpec "let" 方法错误地返回 nil
【发布时间】:2013-07-29 17:31:09
【问题描述】:

我在使用 let 的 RSpec 测试中遇到了一个奇怪的行为。我在使用let 时从来没有遇到过问题,这就是为什么这很奇怪。在以下测试中,my_model let 定义返回 nil:

describe '.process' do
  let(:my_model){ Fabricate(:my_model) }

  it 'doesnt work' do
    # my_model returns nil but it should be returning the fabricated model
    my_model = Processor.process(my_model)
    my_model.special_attribute.should == 'foo'
  end

  it 'works' do
    my_model = Fabricate(:my_model)
    # my_model is now correctly fabricated
    my_model = Processor.process(my_model)
    my_model.special_attribute.should == 'foo'
  end
end

为什么会这样?

【问题讨论】:

    标签: rspec


    【解决方案1】:

    这里的问题是您在调用my_model 之前 使用左手赋值my_modellet 创建了一个名为 my_method 的方法,但是通过首先分配一个名为 my_method 的值,您将使用 nil 局部变量来隐藏该方法。

    您应该在it "doesn't work" 的第一个非注释行中使用不同的变量名。如果你运行这个测试:

    it 'doesnt work' do
      puts defined?(my_model)
      my_model = (puts defined?(my_model)) && process(my_model)
    end
    

    您将获得以下输出:

    method
    local-variable
    

    一旦您分配了一个值(而不是调用此范围内不存在的my_model= 方法),您将创建一个局部变量,该变量将隐藏该方法并阻止它被调用。你可以用普通的 Ruby 轻松地说明这一点:

    class Foo
      def bar
        "BAR"
      end
    
      def run
        bar = bar.downcase
      end
    end
    
    Foo.new.run
    
    # bar.rb:11:in `run': undefined method `downcase' for nil:NilClass (NoMethodError)
    #    from bar.rb:15:in `<main>'
    

    This blog post 可能有助于进一步阐明问题。

    【讨论】:

    • 就是这样,谢谢!我想我认为它会从右到左进行评估,但显然不是这样。
    • 确实如此,只是局部变量是在到达行时而不是在评估时定义的。我以前记得为什么,但我必须去 VM 源了解细节。
    猜你喜欢
    • 2014-07-22
    • 1970-01-01
    • 1970-01-01
    • 2011-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-12
    相关资源
    最近更新 更多