如何在 Rspec 3.5 中测试模块中的内核睡眠方法?

Chr*_*ugh 1 ruby kernel rspec ruby-on-rails

我在模块的私有部分有以下方法......

  def add_api_delay
    sleep(retry_delay * (retry_multiplier_adjustment - retries)) if retries.positive?
  end
Run Code Online (Sandbox Code Playgroud)

到目前为止,我正在使用的规范看起来像这样......

  let!(:klass) do
    Class.new do
      include AmazonMws::Shared::Utilities
      attr_accessor :retries, :retry_multiplier_adjustment, :retry_delay
      def initialize
        @retries = 1
        @retry_delay = 1
        @retry_multiplier_adjustment = 2
      end

      def test_add_api_delay
        add_api_delay
      end
    end
  end

  describe '.add_api_delay', focus: true do
    # let(:kernel_spy) { class_spy(Kernel, sleep: true) }

    before do

    end

    it 'sleeps retry api calls' do
      # allow(klass).to receive(:sleep).with(1).and_return(kernel_spy)
      # expect(kernel_spy).to have_received(:sleep)
      # expect(Kernel).to receive(:sleep).with(1)
      expect(Kernel).to receive(:sleep).and_return(true)
      klass.new.test_add_api_delay
    end
  end
Run Code Online (Sandbox Code Playgroud)

我有几个目标和原因想测试这个私有方法,但是如何验证 sleep 是否已被调用。我不想减慢套件的速度,所以理想情况下我尝试对内核使用类间谍。我正在测试的任何东西似乎都不起作用。

更新

  describe '.add_api_delay' do
    before do
      allow_any_instance_of(klass).to receive(:sleep).and_return(1)
    end

    it 'sleeps retry api calls' do
      expect(klass.new.test_add_api_delay).to eq(1)
    end
  end
Run Code Online (Sandbox Code Playgroud)

然而,这有效,但并不理想,因为它标记了以下警察......

C: RSpec/AnyInstance: Avoid stubbing using allow_any_instance_of
      allow_any_instance_of(klass).to receive(:sleep).and_return(1)
Run Code Online (Sandbox Code Playgroud)

你怎么看?

小智 5

我相信它不起作用,因为你没有把期望放在正确的事情上。看起来您已经尝试将其放在Kernel, 和被测试的类上,但您需要将其放在实例上:

it 'sleeps retry api calls' do
  thing = klass.new
  allow(thing).to receive(:sleep)

  thing.test_add_api_delay

  expect(thing).to have_received(:sleep).with(1)
end
Run Code Online (Sandbox Code Playgroud)

上面有一种测试味道,因为它正在破坏被测试的类。但我认为这可能比在这里强制执行一些设计约束并在仅仅调用 时失去 Ruby 的一些优雅要好sleep