[rspec-users] How To Spec Controllers with Finders
s.ross
cwdinfo at gmail.com
Sat Jan 6 12:09:10 EST 2007
Wow! Thanks. I'll look at this to see how it works for me.
Steve
On Jan 6, 2007, at 5:20 AM, David Chelimsky wrote:
> On 1/6/07, s.ross <cwdinfo at gmail.com> wrote:
>> What I came up with was:
>>
>> context "The cart controller" do
>> controller_name "carts"
>> integrate_views
>>
>> setup do
>> @cart = mock("cart")
>> @cart.stub!(:new_record).and_return(false)
>> @cart.stub!(:new).and_return(@cart)
>> @cart.stub!(:total_price).and_return(35.00)
>> @cart.stub!(:total_quantity).and_return(1)
>> @cart.stub!(:empty?).and_return(false)
>>
>> @line_item = mock("line_item")
>> LineItem.stub!(:find_by_id).and_return(@line_item)
>> @line_item.should_receive(:update_attribute).with(:quantity,
>> "1").and_return(true)
>
> I try to avoid using should_receive in setup, so I'd do this here:
>
> @line_item.stub!(:update_attribute).and_return(true)
>
> and then override the method stub w/ a mock expectation in the specify
> block. The idea is that you put all of the stuff in setup that must be
> there for the code to execute, and put the details in the specs that
> are interesting for that spec.
>
>> @line_item.stub!(:extension).and_return(25.00)
>> end
>>
>> specify "should allow change of quantity" do
>> post :change_quantity, {:id => 1, :quantity => 1}
>> response.should_be_success
>> assigns[:extension_id].should == "extension1"
>> assigns[:line_item].should_be(@line_item)
>> controller.should_render_rjs :replace_html, 'cartstatus',
>> "(1 item, $35.00)"
>> end
>> end
>>
>> but somehow it seems a bit brittle. This is really what should happen
>> if a user changes quantity, but the mocks seem like they won't flex
>> or bend easily for further reuse. Any thoughts on this?
>
> Within this context they absolutely will flex or bend by overriding
> the method stubs (functioning as defaults) w/ mock expectations.
>
> Also, I might approach this differently. The behaviour here that you
> want to spec is that when changing quantity some things should happen.
> So....
>
> context "Given a request to change quantity, the CartController
> should" do
> controller_name "carts"
> integrate_views
>
> setup do
> @cart = mock("cart")
> @cart.stub!(:new_record).and_return(false)
> @cart.stub!(:total_price).and_return(35.00)
> @cart.stub!(:total_quantity).and_return(1)
> @cart.stub!(:empty?).and_return(false)
> Cart.stub!(:new).and_return(@cart)
>
> @line_item = mock("line_item")
> @line_item.stub!(:update_attribute).and_return(true)
> @line_item.stub!(:extension).and_return(25.00)
> LineItem.stub!(:find_by_id).and_return(@line_item)
>
> post :change_quantity, {:id => 1, :quantity => 1}
> end
>
> specify "respond w/ success" do
> response.should_be_success
> end
>
> specify "assign exension_id" do
> assigns[:extension_id].should == "extension1"
> end
>
> specify "assign line_item" do
> assigns[:line_item].should_be(@line_item)
> end
>
> specify "update the html (using rjs)" do
> controller.should_render_rjs :replace_html,
> 'cartstatus',
> "(1 item, $35.00)"
> end
> end
>
> This would then read:
>
> Given a request to change quantity, the CartController should
> - respond w/ success
> - assign exension_id
> - assign line_item
> - update the html (using rjs)
>
> If you're concerned about reuse of the stubs, you can do this:
>
> module Stubs
> def new_stub_cart
> cart = mock("cart")
> cart.stub!(:new_record).and_return(false)
> cart.stub!(:total_price).and_return(0.0)
> cart.stub!(:total_quantity).and_return(0)
> cart.stub!(:empty?).and_return(false)
> cart
> end
>
> def new_stub_line_item
> line_item = mock("line_item")
> line_item.stub!(:update_attribute).and_return(true)
> line_item.stub!(:extension).and_return(0)
> line_item
> end
>
> def stub_cart
> @stub_cart ||= new_stub_cart
> end
>
> def stub_line_item
> @stub_line_item ||= new_stub_line_item
> end
> end
>
> context "Given a request to change quantity, the CartController
> should" do
> include Stubs
> controller_name "carts"
> integrate_views
>
> setup do
> Cart.stub!(:new).and_return(stub_cart)
> LineItem.stub!(:find_by_id).and_return(stub_line_item)
> end
> ...
> end
>
> Now any new spec that requires specific values can use
> stub_cart.should_receive(:total_price).and_return(25.00), for example.
>
>
>>
>> On Jan 5, 2007, at 2:14 PM, Courtenay wrote:
>>
>>> try this:
>>>
>>>
>>> @line_item = mock("line_item")
>>> LineItem.should_receive(:find_by_id).with(3).and_return(@line_item)
>>> @line_item.should_receive(:update_attribute).with(:quantity, 1)
>>>
>>> get :change_quantity, :id => 3, :quantity => 1
>>>
>>>
>>> On 1/5/07, s.ross <cwdinfo at gmail.com> wrote:
>>>> Given this code (which renders rjs), I'm faced with the fixture-
>>>> driven way of spec-ing or mocking. How the heck to you mock this so
>>>> the code at line (2) and (4) work right? I'm still struggling with
>>>> mocks but it seems like this can be done. Forgive the naivety of
>>>> this
>>>> question.
>>>>
>>>> 1. def change_quantity
>>>> 2. @line_item = LineItem.find_by_id(params[:id])
>>>> 3. unless @line_item.nil?
>>>> 4. @line_item.update_attribute(:quantity, params[:quantity])
>>>> 5. @extension_id = "extension#{params[:id]}"
>>>> 6. end
>>>> 7. end
>>>>
>>>> Thanks
>>>> _______________________________________________
>>>> rspec-users mailing list
>>>> rspec-users at rubyforge.org
>>>> http://rubyforge.org/mailman/listinfo/rspec-users
>>>>
>>> _______________________________________________
>>> rspec-users mailing list
>>> rspec-users at rubyforge.org
>>> http://rubyforge.org/mailman/listinfo/rspec-users
>>
>> _______________________________________________
>> rspec-users mailing list
>> rspec-users at rubyforge.org
>> http://rubyforge.org/mailman/listinfo/rspec-users
>>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
More information about the rspec-users
mailing list