2014-10-02 19 views
0

所以我在測試Ruby類時遇到了這種奇怪的行爲。順便說一句,我使用rspec 3來測試它。Ruby + Rspec + OpenStruct怪異行爲

Foo類有一個方法'fetch_object',它調用類Bar中的'find'方法來檢索一個對象,並從獲取的對象中調用方法'fail'。

時,我期望得到法「失敗」一次收到沒有,但如果我爲「faill」改變方法的名稱它就像一個魅力的所謂怪異的行爲發生:S

這裏是劇:

require 'ostruct' 

class Foo 

    def fetch_object 
    foobar = Bar.find 
    foobar.fail 
    end 

end 

class Bar 

    def self.find 
    OpenStruct.new(name: 'Foo Bar') 
    end 

end 

describe Foo do 

    subject { Foo.new } 

    let(:foo) { OpenStruct.new() } 

    before do 
    expect(Bar).to receive(:find).and_return(foo) 
    end 

    it 'fetch object with name' do 
    expect(foo).to receive(:fail) 
    subject.fetch_object 
    end 

end 
+0

時我運行你的代碼我得到了'失敗/錯誤:expect(Bar).to接收(:find).and_return(foo) ().find(任何參數) 預期: ts 收到:使用任何參數0次 – Anthony 2014-10-02 00:33:06

回答

0

我懷疑這是因爲你設置的對象的預期,其行爲取決於method_missingOpenStruct)。

出於這個原因,我不希望它作爲假的,我會用普通模擬(和規範將通過):

let(:foo) { double('foobar') } 

您在這裏測試,如果返回的對象(Bar.find的結果)將收到預期的消息,而不會涉及實現細節。

對像ostruct這樣的動態類設置期望可能會導致奇怪的結果。看起來在某個時候調用了一個Kernel#fail方法,因此,將名稱更改爲faill或任何其他未被內核「取走」的方法將使其工作。

其他解決辦法是的Monkeypatching OpenStruct避免method_missing beeing稱爲:

class OpenStruct 
    def fail 
    true 
    end 
end 

class Foo 

    def fetch_object 
    foobar = Bar.find 
    foobar.fail 
    end 

end 

class Bar 

    def self.find 
    OpenStruct.new(name: 'Foo Bar') 
    end 

end 

describe Foo do 

    subject { Foo.new } 

    let(:foo) { OpenStruct.new } 

    before do 
    expect(Bar).to receive(:find).and_return(foo) 
    end 

    it 'fetch object with name' do 
    expect(foo).to receive(:fail) 
    subject.fetch_object 
    end 

end 

但我不知道你爲什麼會想這樣做;)

更多信息:Doubles and dynamic classess