ruby RSpec:stubbing Kernel::sleep?

pgx2nnw8  于 2023-08-04  发布在  Ruby
关注(0)|答案(9)|浏览(104)

有没有办法在rspec场景中清除Kernel.sleep?

nkoocmlb

nkoocmlb1#

如果你在一个对象的上下文中调用sleep,你应该在对象上存根它,像这样:

class Foo
  def self.some_method
    sleep 5
  end
end

it "should call sleep" do
  Foo.stub!(:sleep)
  Foo.should_receive(:sleep).with(5)
  Foo.some_method
end

字符串
关键是,在调用sleep的上下文中,将sleep置于任何“自我”之上。

wmomyfyw

wmomyfyw2#

当对sleep的调用不在对象内时(例如,在测试rake任务时),您可以在before块中添加以下内容(rspec 3语法)

allow_any_instance_of(Object).to receive(:sleep)

字符串

tkqqtvp1

tkqqtvp13#

如果你使用的是Mocha,那么下面的代码就可以工作:

def setup
  Kernel.stubs(:sleep)
end

def test_my_sleepy_method
  my_object.take_cat_nap!
  Kernel.assert_received(:sleep).with(1800) #should take a half-hour paower-nap
end

字符串
如果你使用rr

def setup
  stub(Kernel).sleep
end

def test_my_sleepy_method
  my_object.take_cat_nap!
  assert_received(Kernel) { |k| k.sleep(1800) }
end


你可能不应该用单元测试来测试更复杂的线程问题。但是,在集成测试中,请使用真实的的Kernel.sleep,它将帮助您找出复杂的线程问题。

ct3nt3jp

ct3nt3jp4#

在纯rspec中:

before do
  Kernel.stub!(:sleep)
end

it "should sleep" do
  Kernel.should_receive(:sleep).with(100)
  Object.method_to_test #We need to call our method to see that it is called
end

字符串

imzjd6km

imzjd6km5#

下面是使用Kernal::Sleep对Rspec进行存根的新方法。
这基本上是对以下答案的更新:Tony Pitluga's answer to the same question

class Foo
  def self.some_method
    sleep 5
  end
end

it "should call sleep" do
  allow_any_instance_of(Foo).to receive(:sleep)
  expect(Foo).to receive(:sleep).with(5)
  Foo.some_method
end

字符串

7nbnzgx9

7nbnzgx96#

对于rspec版本1,stubbing语法已更改。这个方法的作用是:

allow_any_instance_of(Kernel).to receive(:sleep).and_return("")

字符串
当我使用它。

6jygbczu

6jygbczu7#

我需要存根要求,经过长时间的搜索,我发现,唯一的方式,为我工作是这样的

def method_using_sleep
  sleep
  sleep 0.01
end

it "should use sleep" do
  @expectations = mock('expectations')
  @expectations.should_receive(:sleep).ordered.with()
  @expectations.should_receive(:sleep).ordered.with(0.01)

  def sleep(*args)
    @expectations.sleep(*args)
  end

  method_using_sleep
end

字符串

xzabzqsa

xzabzqsa8#

我无法让这里的其他解决方案发挥作用。也许在Ruby的新版本中,处理睡眠的方式发生了变化,或者其他什么。
我最终做的是给Object类打了一个猴子补丁,因为它似乎是接收睡眠调用的对象。所以我简单地加了这个:

class Object
    def sleep(*args)
    end
end

字符串
所以睡眠方法现在什么也不做,而是做了一些事情。可能有一些更好的方法来模拟它,但是如果不模拟可能使用它的每个对象的sleep metohd,我就找不到一个好的解决方案。

c3frrgcw

c3frrgcw9#

由于Kernel是所有Object的祖先,因此应该能够在测试类上模拟继承的sleep方法。

MyClass.ancestors --> [MyClass, Object, PP::ObjectMixin, Kernel, BasicObject]

字符串
模拟可以用类似于下面的代码完成。

before do
  allow(described_class).to receive(:sleep).and_return('')
end


下面更详细的示例显示了在类和示例方法中调用sleep时的模拟。希望听到更多有经验的Ruby开发人员的评论。
类别:

class MyClass
  class << self
    def klass_action(sleep_seconds)
      sleep(sleep_seconds)
    end
  end

  def self.class_action(sleep_seconds)
    sleep(sleep_seconds)
  end

  def do_some_action(sleep_seconds)
    sleep(sleep_seconds)
  end
end


测试:

describe MyClass, focus: true do
  subject { MyClass.new }

  let(:sleep_seconds) { 12 }

  context 'sleep called from an instance' do
    before do
      allow(subject).to receive(:sleep).and_return('')
    end

    it 'sleeps for the requested number of seconds' do
      subject.do_some_action(sleep_seconds)

      expect(subject).to have_received(:sleep).with(sleep_seconds)
    end
  end

  context 'sleep called from a class' do
    before do
      allow(described_class).to receive(:sleep).and_return('')
    end

    it 'class method sleeps for the requested number of seconds' do
      described_class.class_action(sleep_seconds)

      expect(described_class).to have_received(:sleep).with(sleep_seconds)
    end

    it 'klass method sleeps for the requested number of seconds' do
      described_class.klass_action(sleep_seconds)

      expect(described_class).to have_received(:sleep).with(sleep_seconds)
    end
  end
end

相关问题