Rspec:访问Klass.any_instance.stub块中的实例

art*_*ave 5 ruby tdd bdd rspec

Feature: test randomness
    In order to make some code testable
    As a developer
    I want Array#sample to become Array#first
Run Code Online (Sandbox Code Playgroud)

如果有人可以访问Klass.any_instance.stub块中的实例,那么这是可能的.像这样的东西:

Array.any_instance.stub(:sample) { instance.first }
Run Code Online (Sandbox Code Playgroud)

但是那个afaik是不可能的.

无论如何,想要的场景!

Kel*_*vin 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
Run Code Online (Sandbox Code Playgroud)

然后在你的例子中:

Array.any_instance.stub(:sample) do
  instance = any_instance_receiver
  instance.first
end
Run Code Online (Sandbox Code Playgroud)

我对堆栈搜索设置了限制,以避免搜索巨大的堆栈。我不明白为什么你需要增加它,因为它应该始终存在cur_idx == 8

请注意,binding_of_caller在生产中可能不建议使用。