开发者

Rspec: access to instance inside Klass.any_instance.stub block

Feature: test randomness
    In order to make some code testable
    As a developer
    I want Array#sample to become Array#first

It would be possible if one could access instance inside Klass.any_instance.stub block. Something like this:

Array开发者_JS百科.any_instance.stub(:sample) { instance.first }

But that afaik is not possible.

Anyway, scenarios wanted!


I found a hacky solution, which I've tested on rspec versions 2.13.1 and 2.14.4. You'll need the binding_of_caller gem.

Helper method - this should be callable by your rspec example:

# 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

Then in your example:

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

I've set a limit on the stack searching, to avoid searching a huge stack. I don't see why you'd need to increase it, since it should always be around cur_idx == 8.

Note that using binding_of_caller is probably not recommended in production.


For those stumbling across this now, Rspec 3 implements this functionality via the first argument in the block passed to stub:

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 }

I found this here.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜