[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