[rspec-users] Stubbing Scopes

Christoph Schiessl chs at proactive.cc
Thu Feb 24 15:34:58 EST 2011


So...

I settled for testing with message expectations without return values. Guess that's good enough for now. Thank you anyway!

Best regards,
Christoph Schiessl

On Feb 15, 2011, at 21:34 , Justin Ko wrote:

> 
> 
> On Feb 15, 11:14 am, Christoph Schiessl <c... at proactive.cc> wrote:
>> Thanks for your suggestion Justin, but I don't believe that the problem is time zone related. Time objects usually don't "loose" their Time Zone when performing operations on them. Here's an example for illustration:
>> 
>> $ rails console
>> Loading development environment (Rails 3.0.4)
>> ruby-1.8.7-p330 :001 > Time.zone.name
>>  => "Vienna"
>> ruby-1.8.7-p330 :002 > t = Time.zone.now.beginning_of_month
>>  => Tue, 01 Feb 2011 00:00:00 CET +01:00
>> ruby-1.8.7-p330 :003 > t += 3.hours
>>  => Tue, 01 Feb 2011 03:00:00 CET +01:00
>> ruby-1.8.7-p330 :004 > t.beginning_of_day
>>  => Tue, 01 Feb 2011 00:00:00 CET +01:00
>> 
>> If the should_receive arguments and actual arguments wouldn't be the same, then I would expect both examples below to fail.
>> 
>>   context ".on_day" do
>>     let(:start_of_day) { Time.zone.now.beginning_of_day }
>>     before { Interval.should_receive(:in_interval).with(start_of_day, start_of_day + 1.day).and_return("result") }
>>     # (1) Passing example:
>>     it { Interval.on_day(start_of_day + 3.hours) }
>>     # (2) Failing example:
>>     it { Interval.on_day(start_of_day + 3.hours).should == "result" }
>>   end
>> 
>> However, (1) is passing and (2) is failing. Output as before:
>> 
>>>>   Failure/Error: Allocation.on_day(start_of_day + 3.hours).should == "result"
>>>>   NoMethodError:
>>>>     undefined method `includes_values' for "result":String
>> 
>> Any ideas?
>> 
>> Best regards,
>> Christoph Schiessl
>> 
>> On Feb 15, 2011, at 18:51 , Justin Ko wrote:
>> 
>> 
>> 
>> 
>> 
>>> Your expectation (should_receive) is expecting "start_of_day", which
>>> uses Time.zone. The actual "on_day" scope does
>>> "day.to_time.beginning_of_day", which does not use any time zone.
>>> Therefore, the arguments to in_interval are not the same as the
>>> expectation. And because they are not the same, the mock does not get
>>> set. They must be exactly the same, since you are using a specific
>>> values.
>> 
>>> You are not seeing a "the in_interval method was not called"
>>> expectation ouput message because of the "includes_values" error. This
>>> is because RSpec is comparing "result" with an array. This is because
>>> Rails scopes return arrays, not strings (it is not returning a string
>>> because the mock was never set).
>> 
>>> Are you setting the time zone in a before block?
>> 
>>> Here are two really nice gems for dealing with Time sensitive code:
>>> https://github.com/jtrupiano/timecop
>>> https://github.com/bebanjo/delorean
>> 
>>> On Feb 15, 9:35 am, Christoph Schiessl <c... at proactive.cc> wrote:
>>>> Hi!
>> 
>>>> I'm trying to test the following (simplified) model:
>> 
>>>> class Allocation < ActiveRecord::Base
>>>>   scope :in_interval, (proc do |start_of_interval, end_of_interval|
>>>>     params = {:s => start_of_interval, :e => end_of_interval}
>>>>     where("(starts_at > :s AND starts_at < :e) OR (ends_at > :s AND ends_at < :e) OR (starts_at <= :s AND ends_at >= :e)", params)
>>>>   end)
>> 
>>>>   scope :on_day, (proc do |day|
>>>>     day = day.to_time.beginning_of_day
>>>>     in_interval(day, day + 1.day)
>>>>   end)
>> 
>>>>   # validations and other scopes...
>>>> end
>> 
>>>> I wrote a lot of specs for :in_interval - however testing :on_day is kind of problem. I don't want to duplicate any :in_interval specs - therefore I'm trying to stub :in_interval like this:
>> 
>>>> let(:start_of_day) { Time.zone.now.beginning_of_day }
>>>> it do
>>>>   Allocation.should_receive(:in_interval).with(start_of_day, start_of_day + 1.day).and_return("result")
>> 
>>>>   # working assertion - the :in_interval stub seems to get called as expected:
>>>>   # Allocation.on_day(start_of_day + 3.hours)
>> 
>>>>   # failing assertion:
>>>>   Allocation.on_day(start_of_day + 3.hours).should == "result"
>>>> end
>> 
>>>> RSpec Output:
>> 
>>>>   Failure/Error: Allocation.on_day(start_of_day + 3.hours).should == "result"
>>>>   NoMethodError:
>>>>     undefined method `includes_values' for "result":String
>> 
>>>> I'm using Rails 3.0.4 and RSpec 2.5 (latest versions).
>> 
>>>> Best regards,
>>>> Christoph Schiessl
>>>> _______________________________________________
>>>> rspec-users mailing list
>>>> rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users
>>> _______________________________________________
>>> rspec-users mailing list
>>> rspec-us... at rubyforge.org
>>> http://rubyforge.org/mailman/listinfo/rspec-users
>> 
>> _______________________________________________
>> rspec-users mailing list
>> rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users
> 
> Maybe because the scope is being called within a scope, it is wrapping
> it in an array: ["results"]
> 
> Either way, report back what this code returns: it { raise
> Interval.on_day(start_of_day + 3.hours).inspect }
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users



More information about the rspec-users mailing list