2013-07-29 71 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的具體細節。 –