2011-05-31 58 views
5
Feature: test randomness 
    In order to make some code testable 
    As a developer 
    I want Array#sample to become Array#first 

如果可以訪問Klass.any_instance.stub塊內的實例,那將是可能的。事情是這樣的:Rspec:訪問Klass.any_instance.stub塊中的實例

Array.any_instance.stub(:sample) { instance.first } 

但是,據我所知是不可能的。

無論如何,想要的情景!

回答

2

我發現了一個hacky解決方案,我在rspec版本2.13.1和2.14.4上測試過。你需要binding_of_caller寶石。

助手方法 - 這應該由你的rspec的例子可調用:

# must be called inside stubbed implementation 
def any_instance_receiver(search_limit = 20) 
    stack_file_str = 'lib/rspec/mocks/any_instance/recorder.rb:' 
    found_instance = nil 
    # binding_of_caller's notion of the stack is different from caller(), so we need to search 
    (1 .. search_limit).each do |cur_idx| 
    frame_self, stack_loc = binding.of_caller(cur_idx).eval('[self, caller(0)[0]]') 
    if stack_loc.include?(stack_file_str) 
     found_instance = frame_self 
     break 
    end 
    end 
    raise "instance not found" unless found_instance 
    return found_instance 
end 

然後在你的榜樣:

Array.any_instance.stub(:sample) do 
    instance = any_instance_receiver 
    instance.first 
end 

我設置堆棧搜索的限制,以避免搜索一巨大的堆棧。我不明白你爲什麼需要增加它,因爲它應該總是在cur_idx == 8左右。

請注意,在生產中可能不推薦使用binding_of_caller

0

對於那些通過在傳遞給stub塊中的第一個參數跨越這個現在,Rspec的3實現此功能絆:

RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks = true # I believe this is the default 

Array.any_instance.stub(:sample) { |arr| arr.first } 

我發現這個here