RSpec: stubbing Kernel::sleep?

Is there a way to stub Kernel.sleep in an rspec scenario?


Solution 1:

If you are calling sleep within the context of an object, you should stub it on the object, like so:

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

The key is, to stub sleep on whatever "self" is in the context where sleep is called.

Solution 2:

When the call to sleep is not within an object (while testing a rake task for example), you can add the following in a before block (rspec 3 syntax)

allow_any_instance_of(Object).to receive(:sleep)

Solution 3:

If you're using Mocha, then something like this will work:

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

Or if you're using 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

You probably shouldn't be testing more complex threading issues with unit tests. On integration tests, however, use the real Kernel.sleep, which will help you ferret out complex threading issues.

Solution 4:

In pure 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

Solution 5:

Here's the newer way of stubbing Rspec with Kernal::Sleep.

This is basically an update to the following answer: 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