Reputation: 8178
In my codes, there are many places I purposely puts "sleep", just because the features are required to be so. However, when I do testing using RSpec or Cucumber, it becomes a nuisance because it takes so long to complete the tests.
Updated: thanks for some of the suggestions. However either stub or manually redefining might be cumbersome. What I imagine is just a tweak call to speed up "sleep" with a scale.
There is this gem timecop. It can speed up Time.now by a scale. If such idea can be applied to sleep, that would be great!
Reference: https://github.com/travisjeffery/timecop
Updated:sorry for late response, below may illustrate my situation:
class SomeClass
def some_method
sleep 15
make_api_call_A
sleep 45
make_api_call_B
end
end
describe SomeClass do
before do
Acceleration.speed_up(10) # speed time up to 10x
end
after do
Acceleration.reset
end
if "should make two API calls" do
subject.some_method
end
end
As you can see there are two sleeps with different durations in some_method. What I prefer is, instead of waiting 60s, if I can speed up sleep time to 10x, I just have to wait for 6s. That fastens the testing process a lot.
Upvotes: 1
Views: 2621
Reputation: 272
There is a solution which in my opinion is easier and doesn't add more dependencies to your project:
In the class, put the sleep time into a constant, for example:
WAITING_TIME = 45
Call sleep
with this constant instead of a number:
sleep WAITING_TIME
In the test use stub_const
from RSpec
to change the time used for sleeping:
before do
stub_const('MyClass::WAITING_TIME', 4.5)
end
That is all. You don't need to mock the sleep
call, you don't need an additional gem for this, and RSpec
will take care of stubbing the constant and resetting it back at the end of the test.
Upvotes: 1
Reputation: 504
If you want to scale sleep, you can override Kernel.sleep
method this way:
module Acceleration
mattr_accessor :sleep_scale
def self.speed_up(scale)
self.sleep_scale = scale
end
def self.reset
self.sleep_scale = 1
end
reset
end
module Kernel
alias :original_sleep :sleep
def sleep(time)
original_sleep(time / Acceleration.sleep_scale.to_f)
end
end
class SomeClass
def some_method
sleep 15
make_api_call_A
sleep 45
make_api_call_B
end
end
describe SomeClass do
before do
Acceleration.speed_up(10) # speed time up to 10x
end
after do
Acceleration.reset
end
it "should make two API calls" do
subject.some_method
end
end
Upvotes: 2
Reputation: 84353
Assuming that you really have a valid use case here, and you don't want to refactor your code to avoid hard-coded sleep values or disable sleeping altogether, you can simply monkey-patch Kernel#sleep within your specs to use a scaled factor. For example, to make sleep run ten times faster (e.g. for 1/10 the specified time):
module Kernel
alias_method :old_sleep, :sleep
def sleep seconds
old_sleep(seconds * 0.1)
end
end
Once you've monkey-patched sleep, you can test that your scaling works with Benchmark#realtime:
require 'benchmark'
Benchmark.realtime { sleep 10 }.round 2
#=> 1.0
Benchmark.realtime { sleep 0.1 }.round 2
#=> 0.01
Upvotes: 0
Reputation: 504
You need stub sleep
calls in your specs.
class SomeClass
def some_method
sleep 10
end
end
describe SomeClass do
before do
subject.stub!(:sleep)
end
it "should call sleep" do
subject.should_receive(:sleep).with(10)
subject.some_method
end
end
Upvotes: 4