2013-07-29 53 views
1

我在使用let的RSpec测试中遇到了一个奇怪的行为。我从来没有遇到过使用let的问题,所以这很奇怪。在下面的测试中,my_modellet定义返回nil:RSpec“让”方法错误地返回零

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

这里的问题是,您正在使用my_model的左侧任务,然后my_model被调用。 let创建了一个名为my_method的方法,但首先通过指定一个名为my_method的值,您将该方法映射到一个无局部变量。

您应该在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可能有助于阐明这个问题进一步。

+0

就是这样,谢谢!我想我认为它会评估从右到左,但显然不是这样。 – Andrew

+0

它的确有,除了局部变量在达到该行时被定义而不是在被评估时被定义。我曾经记得为什么,但我不得不去VM的具体细节。 –