I''m having trouble working out how to test a method that contains a loop. I''m new to rspec so not sure what the best way is to tackle this. class Company < ActiveRecord::Base def self.sync_with_basecamp companies = basecamp_fetch("companies") companies.each do |c| company = self.find_or_initialize_by_name_and_postcode(c.name, c.zip) company.county = c.state company.city = c.city company.save end end end I started by checking that the number of companies in my mock companies array was saved: it "should write all records from array to the database" do lambda { Company.sync_with_basecamp }.should change(Company, :count).by(37) end But I''m having trouble figuring out how to check individual records. I can pull the first record from the mock array: it "should populate name" do @company.first.name.should eql("The Media Collective") end But I can''t check that this has been applied to the method because rspec doesn''t know about the save loop. it "should populate name" do @company.name.should eql("The Media Collective") end Would appreciate some advice on how to tackle this please from someone more familiar with rspec than me.
On Feb 4, 2008 5:24 AM, David Currin <dave at 2young2die.com> wrote:> I''m having trouble working out how to test a method that contains a > loop. I''m new to rspec so not sure what the best way is to tackle > this. > > class Company < ActiveRecord::Base > > def self.sync_with_basecamp > companies = basecamp_fetch("companies") > > companies.each do |c| > company = self.find_or_initialize_by_name_and_postcode(c.name, c.zip) > company.county = c.state > company.city = c.city > company.save > end > > end > > end > > I started by checking that the number of companies in my mock > companies array was saved: > > it "should write all records from array to the database" do > lambda { > Company.sync_with_basecamp > }.should change(Company, :count).by(37) > end > > But I''m having trouble figuring out how to check individual records. I > can pull the first record from the mock array: > > it "should populate name" do > @company.first.name.should eql("The Media Collective") > endIt depends on how clearly you want to isolate from the database. Your first example is going to hit the DB 37 times. I wouldn''t do that personally. Even if I was hitting the database I''d reduce that dataset to one or two records. The way I''d approach this if I were trying to isolate from the DB would be like this: @company = mock_model(Company) Company.should_receive(:basecamp_fetch). with("companies"). and_return([@company]) # ... expectations about @company HTH, David> > But I can''t check that this has been applied to the method because > rspec doesn''t know about the save loop. > > it "should populate name" do > @company.name.should eql("The Media Collective") > end > > > Would appreciate some advice on how to tackle this please from someone > more familiar with rspec than me. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20080204/cafe800f/attachment.html
Thanks, Point taken about less interaction with the database. The ''companies'' mock is an exact representation of the companies list returned by the basecamp api which is why there''s 37 records in there. I need to learn to think more clearly about separation from the database I guess. The point is actually that none of these examples are touching the database at the moment because rspec doesn''t know about the companies.each do loop in the model. I''m wanting to cycle through the list of companies in the fetched array and save these as rows in the database. I have done a basic implementation of this in the model, but I can''t get this through to rspec. On 04/02/2008, David Chelimsky <dchelimsky at gmail.com> wrote:> On Feb 4, 2008 5:24 AM, David Currin <dave at 2young2die.com> wrote: > > I''m having trouble working out how to test a method that contains a > > loop. I''m new to rspec so not sure what the best way is to tackle > > this. > > > > class Company < ActiveRecord::Base > > > > def self.sync_with_basecamp > > companies = basecamp_fetch("companies") > > > > companies.each do |c| > > company > self.find_or_initialize_by_name_and_postcode(c.name, c.zip) > > company.county = c.state > > company.city = c.city > > company.save > > end > > > > end > > > > end > > > > I started by checking that the number of companies in my mock > > companies array was saved: > > > > it "should write all records from array to the database" do > > lambda { > > Company.sync_with_basecamp > > }.should change(Company, :count).by(37) > > end > > > > But I''m having trouble figuring out how to check individual records. I > > can pull the first record from the mock array: > > > > it "should populate name" do > > @company.first.name.should eql("The Media Collective") > > end > > It depends on how clearly you want to isolate from the database. Your first > example is going to hit the DB 37 times. I wouldn''t do that personally. Even > if I was hitting the database I''d reduce that dataset to one or two records. > > The way I''d approach this if I were trying to isolate from the DB would be > like this: > > @company = mock_model(Company) > Company.should_receive(:basecamp_fetch). > with("companies"). > and_return([@company]) > # ... expectations about @company > > HTH, > David > > > > > > But I can''t check that this has been applied to the method because > > rspec doesn''t know about the save loop. > > > > it "should populate name" do > > @company.name.should eql("The Media Collective") > > end > > > > > > Would appreciate some advice on how to tackle this please from someone > > more familiar with rspec than me. > > _______________________________________________ > > 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 >
Extract the company creation to a method, so that that method only builds one record at a time. Test that it works properly. Then you can keep the test that you have, verifying that it creates the right number of records. Pat
Great, thanks for that, d. On 04/02/2008, Pat Maddox <pergesu at gmail.com> wrote:> Extract the company creation to a method, so that that method only > builds one record at a time. Test that it works properly. Then you > can keep the test that you have, verifying that it creates the right > number of records. > > Pat > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >