David Chelimsky escreveu:
On Sat, Nov 7, 2009 at 6:18 PM, Carlos Rodriguez <[email protected] <mailto:[email protected]>> 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/
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to