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

Rodrigo Rosenfeld Rosas lbocseg at yahoo.com.br
Sun Nov 8 05:39:31 EST 2009


David Chelimsky escreveu:
> On Sat, Nov 7, 2009 at 6:18 PM, Carlos Rodriguez <carlos at eddorre.com 
> <mailto:carlos at eddorre.com>> wrote:
>
>     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,
>
>
> Hi Carlos,
>
> I would definitely assume that the times are off by milliseconds here 
> and that the to_s method simply produces the same result on two 
> different times.
>
> Not sure why it's still failing even when using Timecop, though. 
> Perhaps somebody else has some ideas about that.

I believe Timecop doesn't help in this case.

ActiveRecord will probably fill the time using SQL now() instead of 
Time.now.

Anyway, I wouldn't bother to test if the time was changed to now. I 
think it suffices to test that time was changed from nil.

If you really want to test that it changed to now, I would write 
something like:

@post.published_at.should be_nil
@post.publish!
(Time.now - @post.published_at).should have_at_most(1).second

Or you could write a new matcher if you need to check this often... But 
I think this is an already tested ActiveRecord behavior and that you 
should test only your code and rely on ActiveRecord to fill the 
corrected timestamp.

Good luck,

Rodrigo.
__________________________________________________
Faça ligações para outros computadores com o novo Yahoo! Messenger 
http://br.beta.messenger.yahoo.com/ 



More information about the rspec-users mailing list