Archive for February 2009

Cucumber step definition tip: Stubbing time

When 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.