Rspec: доступ к экземпляру внутри блока Klass.any_instance.stub - PullRequest
5 голосов
/ 01 июня 2011
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. Как то так:

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

Но этот афайк невозможен.

В любом случае, сценарии нужны!

Ответы [ 2 ]

2 голосов
/ 08 августа 2013

Я нашел хакерское решение, которое я тестировал на версиях 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 голосов
/ 10 июня 2015

Для тех, кто сталкивается с этим сейчас, Rspec 3 реализует эту функциональность через первый аргумент в блоке, передаваемый 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 }

Я нашел это здесь .

...