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

Sería posible si se pudiera acceder a la instancia dentro del bloque Klass.any_instance.stub. Algo como esto:Rspec: acceso a la instancia dentro del bloque Klass.any_instance.stub

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

Pero que afaik no es posible.

De todos modos, los escenarios querían!

Respuesta

2

Encontré una solución hacky, que he probado en las versiones rspec 2.13.1 y 2.14.4. Necesitarás la gema binding_of_caller.

método

Helper - esto debería ser exigible por tu ejemplo 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 

Luego, en tu ejemplo:

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

He establecido un límite en la búsqueda de la pila, para evitar la búsqueda de una gran pila No veo por qué necesitarías aumentarlo, ya que siempre debería estar alrededor de cur_idx == 8.

Tenga en cuenta que el uso de binding_of_caller probablemente no se recomienda en producción.

0

Para aquellos tropezarse con esto ahora, Rspec 3 implementa esta funcionalidad a través del primer argumento en el bloque pasado a 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 encontraron esta here.

Cuestiones relacionadas