Sam Granieri, Jr
2008-Jul-07 06:28 UTC
[rspec-users] Trouble with Association Proxies and new/create in rails
I''m working on some code that uses association proxies. I''m trying to get away from using fixtures, and move more to mocking and stubbing. So far, so good, but the methods I cant figure out, even with extensive googling, are how to simulate the association_proxy.build method in rails. I''m on edge rails and edge rspec. Datawise, a bar has_many suggested_beers, and a suggested_beer belongs to a bar suggested_beers_controller> class SuggestedBeersController < ApplicationController > before_filter :find_bar > > #code omitted for brevity > # GET /bars/1/suggested_beers/new > def new > @suggested_beer = @bar.suggested_beers.build > > respond_to do |format| > format.html > end > end > > # POST /bars/1/suggested_beers > def create > @suggested_beer = > @bar.suggested_beers.build(params[:suggested_beer]) > #more redaction > end > > #code omitted for brevity > private > def find_bar > @bar = Bar.find(params[:bar_id]) > endsuggested_beers_controller_spec.rb This is generated with rspec_scaffold, and i''ve added in the beer_id, bar_id, and ip_address attributes for stubbing.> def mock_suggested_beer(stubs={}) > stubs = { > :save => true, > :update_attributes => true, > :destroy => true, > :to_xml => '''', > :beer_id => "1", > :bar_id => "1", > :ip_address => "127.0.0.1" > }.merge(stubs) > @mock_suggested_beer ||= mock_model(SuggestedBeer, stubs) > end > > describe "responding to GET /bars/1/suggested_beers/new" do > > it "should succeed" do > get :new, :bar_id => "1" > response.should be_success > end > > it "should render the ''new'' template" do > get :new, :bar_id => "1" > response.should render_template(''new'') > end > > it "should create a new suggested_beer" do > > SuggestedBeer.should_receive(:new).and_return(mock_suggested_beer) > get :new, :bar_id => "1" > end"should create a new suggested_beer" fails with this message Spec::Mocks::MockExpectationError in ''SuggestedBeersController responding to GET /bars/1/suggested_beers/new should create a new suggested_beer'' Mock ''SuggestedBeer_1016'' received unexpected message :[]= with ("bar_id", 1) I don''t know how to fix this. I''ve looked at several articles, specifically http://www.lukeredpath.co.uk/2007/10/18/demeters-revenge and http://www.ruby-forum.com/topic/158489 but I''m still confused. Any help is much appreciated! -------------------------------- Sam Granieri, Jr sam at samgranieri.com Chicago, IL irc (freenode): samgranieri http://www.samgranieri.com http://www.beerbin.com Recommend me at WWR! http://www.workingwithrails.com/person/7374-sam-granieri
Rick DeNatale
2008-Jul-07 20:20 UTC
[rspec-users] Trouble with Association Proxies and new/create in rails
On Mon, Jul 7, 2008 at 2:28 AM, Sam Granieri, Jr <sam at samgranieri.com> wrote:> I''m working on some code that uses association proxies. I''m trying to get > away from using fixtures, and move more to mocking and stubbing. So far, so > good, but the methods I cant figure out, even with extensive googling, are > how to simulate the association_proxy.build method in rails. > > I''m on edge rails and edge rspec. > > Datawise, a bar has_many suggested_beers, and a suggested_beer belongs to a > bar > > suggested_beers_controller > > class SuggestedBeersController < ApplicationController >> before_filter :find_bar >> >> #code omitted for brevity >> # GET /bars/1/suggested_beers/new >> def new >> @suggested_beer = @bar.suggested_beers.build >> >> respond_to do |format| >> format.html >> end >> end >> >> # POST /bars/1/suggested_beers >> def create >> @suggested_beer = @bar.suggested_beers.build(params[:suggested_beer]) >> #more redaction >> end >> >> #code omitted for brevity >> private >> def find_bar >> @bar = Bar.find(params[:bar_id]) >> end >> > > > > suggested_beers_controller_spec.rb > > This is generated with rspec_scaffold, and i''ve added in the beer_id, > bar_id, and ip_address attributes for stubbing. > > def mock_suggested_beer(stubs={}) >> stubs = { >> :save => true, >> :update_attributes => true, >> :destroy => true, >> :to_xml => '''', >> :beer_id => "1", >> :bar_id => "1", >> :ip_address => "127.0.0.1" >> }.merge(stubs) >> @mock_suggested_beer ||= mock_model(SuggestedBeer, stubs) >> end >> >> describe "responding to GET /bars/1/suggested_beers/new" do >> >> it "should succeed" do >> get :new, :bar_id => "1" >> response.should be_success >> end >> >> it "should render the ''new'' template" do >> get :new, :bar_id => "1" >> response.should render_template(''new'') >> end >> >> it "should create a new suggested_beer" do >> >> SuggestedBeer.should_receive(:build).with().and_return(mock_suggested_beer) >> get :new, :bar_id => "1" >> end >> > "should create a new suggested_beer" fails with this message > > Spec::Mocks::MockExpectationError in ''SuggestedBeersController responding > to GET /bars/1/suggested_beers/new should create a new suggested_beer'' > Mock ''SuggestedBeer_1016'' received unexpected message :[]= with ("bar_id", > 1) >The way I approach this is to stub the object which has the association proxy to return a mock for the proxy. To do that you have to stub whatever method your controller uses to get that object. In this case, assuming that your controller is setting up @bar in the obvious way, it would be something like. it "should create a new suggested_beer" do suggested_beers = mock("suggested_beers") bar = mock_model(Bar, :suggested_beers => suggested_beers) Bar.stub!(:find).and_return(bar) suggested_beer = mock_model(SuggestedBeer, ....) SuggestedBeer.should_receive(:build).with(:blatz)..and_return(mock_suggested_beer) get :new, :bar_id => "1", :suggested_beer => :blatz end Some would break this down into at least two examples, one just checking that the build method is called and another checking that it is called with the expected paramenters. -- Rick DeNatale My blog on Ruby http://talklikeaduck.denhaven2.com/ -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20080707/217f73a4/attachment-0001.html>