2014-03-12 104 views
0

所以我正在寫一個方法,這會導致向類中添加一些代碼(特別是選擇一個選項並創建一個arel樣式的default_scope)。雖然我玩過簡單的MyClass.send來獲得代碼,但我覺得instance_eval會更清晰,更清晰。instance_eval的Rspec測試結果

# test 
let(:hash) { {order: "my_column desc"} } 
let(:arel) { Proc.new{ order(hash[:order]) } } 
it "converts options hash to arel calls" do 
    MyClass.send(:my_translator_method, hash) 
end 

# method 
def self.my_translator_method(hash) 
    code = method_to_convert_options_to_arel 
    self.instance_eval <<CODE 
    default_scope #{code} 
    CODE 
end 

問題是我不知道如何鉤入類,以確定它是以預期的方式改變。

回答

1

首先,你爲什麼不能這樣做:

self.send(:default_scope, code) 

而不是使用元編程?

其次,你應該總是測試的行爲,而不是實現:

correct_ordered_elements = [.....] 
Myclass.all.should == correct_ordered_elements 
1

我建議是這樣的:

it "converts options hash to arel calls" do 
    expect { MyClass.default_scope }.to raise_error 
    MyClass.my_translator_method hash 
    expect { MyClass.default_scope }.to_not raise_error 
end 

,然後,好措施 - 檢查範圍也是正確的:

it "creates an ordered scope" do 
    MyClass.my_translator_method hash 

    expect(MyClass.default_scope.to_a).to eq MyClass.order("my_column desc").to_a 
end 
1

你應該可以做到這一點與期望類singleton:

let(:code) { method_to_convert_options_to_arel } 
let(:hash) { {order: "my_column desc"} } 

it "sets the default scope" do 
    expect(MyClass).to receive(:default_scope).with(code) 
    MyClass.my_translator_method(hash) 
end 

我認爲你不應該在這裏測試範圍本身 - 爲產生Arel代碼的方法編寫一個單獨的測試。