I’m fairly new to RSpec, and DataMapper and I’m trying to write a
controller
spec for an index action that will include DM query chaining.
Here is a very simplified version of the Controller#index I’m working on
def index @widgets = Widget.all(:order => [ :name.asc ])
if params[:alpha] @widgets = @widgets.by_alpha(params[:alpha])
elsif params[:beta] @widgets = @widgets.by_beta(params[:beta])
end
end
I’m trying to write a spec for this and I’m struggling. It feels like
it’ll
be something uber simple but I’m just not getting it.
describe “GET ‘index’” do
it “should be successful” do
get :index
response.should be_success
end
it “assigns all widgets as @widgets” do
widgets = [Factory.stub(:widget), Factory.stub(:widget)]
Widget.stub(:all) { [widgets] }
get :index
assigns(:widgets).should == [widgets]
end
Would you post the results of your spec? I’d like to see what you’re
getting.
I’m not familiar with DataMapper, but from an Active Record standpoint,
the order clause does not look right. e.g. should be
Square.all.order(:name)
Try running the spec without the order clause in index (e.g. Widget.all)
just to see if that works to rule out the order clause. You might have
to do stub chain on Widget for all and then order.
Thanks Ken, but when I said I was new to RSpec I didn’t mean I was THAT
new!
;o)
I think people aren’t grasping the DataMapper chaining that is at the
root
of my testing confusion. I managed to come up with a solution that I’ve
outlined here http://pastie.org/1690040
Basically, I mocked out a couple DataMapper::Collections and nested
them.
I’d love to hear if anyone would have tackled this issue differently.
DataMapper allows you to chain additional criteria on an existing query
and
doesnt execute that query until in is used in the view. So the above
statement gets baked into the previous default query @widgets =
Widget.all(:order => [ :name.asc ]).
I’d just like to write a test that confirms the controller is in fact
calling @widgets.by_alpha(params[:alpha]) when the params[:alpha] is
present.
Here is the code again so you don’t have to scroll to see it
def index @widgets = Widget.all(:order => [ :name.asc ])
if params[:alpha] @widgets = @widgets.by_alpha(params[:alpha])
elsif params[:beta] @widgets = @widgets.by_beta(params[:beta])
end
end
Just to recap, this code is valid and works, I just don’t know how to
write
a test for it.
Thanks Ken, but when I said I was new to RSpec I didn’t mean I was THAT new! ;o)
I think people aren’t grasping the DataMapper chaining that is at the root of my
testing confusion. I managed to come up with a solution that I’ve outlined here http://pastie.org/1690040
Basically, I mocked out a couple DataMapper::Collections and nested them. I’d
love to hear if anyone would have tackled this issue differently.
Yes, I would have listened to the tests here, and heard that the
interface to my model was awkward.
I would either override Widget#all, or create a new method on the Widget
that simply takes the params hash (or the three specific params new,
name and materials) and figures out what to fetch from the database and
returns it. You have data access concerns leaking out into your
controller, which is why the interface is awkward to mock.