RSpec“let”方法错误地返回nil

时间:2013-07-29 17:31:09

标签: rspec

我在使用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

为什么会这样?

1 个答案:

答案 0 :(得分:2)

这里的问题是,在调用 my_model之前,您正在使用my_model 的左侧作业。 let创建了一个名为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可能有助于进一步阐明问题。