我在使用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
为什么会这样?
答案 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可能有助于进一步阐明问题。