【问题标题】:Rspec: access to instance inside Klass.any_instance.stub blockRspec:访问 Klass.any_instance.stub 块内的实例
【发布时间】:2011-05-31 21:57:55
【问题描述】:
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 }

但那是不可能的。

无论如何,想要的场景!

【问题讨论】:

    标签: ruby rspec tdd bdd


    【解决方案1】:

    我找到了一个 hacky 解决方案,我已经在 rspec 版本 2.13.1 和 2.14.4 上进行了测试。你需要binding_of_caller gem。

    Helper 方法 - 这应该可以由您的 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

    【讨论】:

      【解决方案2】:

      对于那些现在遇到这个问题的人,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 }
      

      我找到了这个here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-13
        • 2021-09-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多