[rspec-users] "lambda Should Change" Behavior Failing When Checking Time

Carlos Rodriguez carlos at eddorre.com
Sat Nov 7 18:18:32 EST 2009


Hello,

I'm having a problem with RSpec when using the "lambda should change behavior".

This is happening in a Rails 2.3.4 app and I'm running the following
in my test environment:

'cucumber', :version => '0.4.2'
'faker', :version => '0.3.1'
'notahat-machinist', :lib => 'machinist', :version => '1.0.3'
"remarkable_rails", :lib => false
'rspec', :lib => false, :version => '1.2.9'
'rspec-rails', :lib => false, :version => '1.2.9'
'jtrupiano-timecop', :lib => 'timecop', :version => '0.3.0'
'webrat', :lib => false, :version => '0.5.1'
'fakeweb', :lib => false, :version => '1.2.6'

In my application, I have a Post model that is using Rubyist's AASM
gem. The aasm column is defined as 'state'. The other column of note
is 'published_at'; this is defined as a datetime.

These are the settings for the state machine:

  aasm_column :state
  aasm_initial_state :draft
  aasm_state :draft
  aasm_state :published, :enter => :set_published
  aasm_event :publish do
    transitions :to => :published, :from => :draft
  end

set_published is a method that is defined as:

  def set_published
    self.update_attributes(:published_at => Time.now)
  end

For those that are unfamiliar with Rubyist's AASM, defining an
aasm_event gives you an bang instance method with the same name of the
aasm_event. For example, I have :publish defined as an aasm_event and
because of this I can call the publish! method on an instance of a
Post. This will change the state from 'draft' to 'published'. It will
also call the set_published method as defined by the :enter statement.

This is my first spec attempt. I've removed all of the post attributes
for brevity.

describe "AASM States" do
  before(:each) do
    @post = Post.create([snip...post attributes here])
  end

  it "should set the publish date to now when transitioning to published" do
    lambda { @post.publish! }.should change(@post,
:published_at).from(nil).to(Time.now)
  end
end

This fails with a message like the following:

published_at should have been changed to Sat Nov 07 15:02:00 -0800
2009, but is now Sat Nov 07 15:02:00 -0800 2009

*blink* *blink*

They appear to be the same.

Just in case the time was being altered by milliseconds that I
couldn't see, I tried using jtrupiano's Timecop gem to freeze time and
check against the frozen time.

    it "should set the publish date to now when transitioning to published" do
      time = Time.now
      Timecop.freeze(time)
      lambda { @post.publish! }.should change(@post,
:published_at).from(nil).to(time)
      Timecop.return
    end

This still gives me the same failure message. For those unfamiliar
with Timecop, here is how it works (in the console):

>> require 'Timecop'
=> []
>> time = Timecop.freeze(Time.now)
=> Sat Nov 07 15:07:32 -0800 2009
>> sleep(10)
=> 10
>> time == Time.now
=> true
>> Timecop.return
=> Sat Nov 07 15:08:09 -0800 2009
>> time == Time.now
=> false

In development, I know that the published_at time is truly
transitioning from nil to an actual time, I just don't know why it's
failing in the spec and even stranger when RSpec tells me that they
are the (supposedly) the same.

>From the development console:

>> p = Post.new([snip...post attributes here])
>> p.save
=> true
>> p.published_at
=> nil
>> p.publish!
=> true
>> p.published_at
=> Sat Nov 07 15:10:22 -0800 2009

Is there something that I'm missing?

Thank you in advance for your help,

Carlos


More information about the rspec-users mailing list