[rspec-users] How To Spec Controllers with Finders
David Chelimsky
dchelimsky at gmail.com
Sat Jan 6 08:20:51 EST 2007
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
>
More information about the rspec-users
mailing list