Cucumber step definition tip: Stubbing time
February 02, 2009When writing Cucumber scenarios, you'll occasionally need to describe a behavior that is dependent on time passing. For example, at weplay we want to ensure that a password reset link expires after one week.
In a RSpec code example, you might be used to stubbing time in this situation:
1 2 3 |
now = Time.now Time.stub!(:now).and_return(now + 8.days) |
This doesn't work out-of-the-box in a Cucumber step definition. By default, Cucumber doesn't include any of RSpec's mocking or stubbing support. This makes sense because Cucumber is a tool for acceptance testing (full stack), where stubbing and especially mocking should be discouraged and only used for very specific purposes (like stubbing time!).
If you find yourself in this situation, you can enable RSpec's stubbing support in your Cucumber step definitions by adding the following code to env.rb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
require "spec/mocks" Before do $rspec_mocks ||= Spec::Mocks::Space.new end After do begin $rspec_mocks.verify_all ensure $rspec_mocks.reset_all end end |
Now you can go ahead and create a time_steps.rb like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
When /^(\d+) minutes pass$/ do |minutes| now = Time.now Time.stub!(:now).and_return(now + minutes.to_i.minutes) end When /^(\d+) hours pass$/ do |hours| now = Time.now Time.stub!(:now).and_return(now + hours.to_i.hours) end When /^(\d+) days pass$/ do |days| now = Time.now Time.stub!(:now).and_return(now + days.to_i.days) end |
RSpec will clear your time stub at the end of each scenario.

So let’s just say you’re being a good developer and you’re writing tests. They are have good coverage (because you’re writing them first), they run fast, and you’ve setup a continuous integration (CI) server (like