I''m having a problems mocking successive return values. I don''t know if I''m doing something wrong or if this is a limitation of rspec mocks. Any ideas of what I may be doing wrong? I''m trying to test the generate_quote_number method. It generates a quote number, looks to see if it is in the db already. If it is, it calls itself to try again. I want to test that it looks in the database for matching numbers until it finds one which does not exist already. ## The code def generate_quote_number quote_num = "MMQ#{self.random_string}-001" if Policy.find(:first, :conditions => ["quote_number = ?", quote_num]) quote_num = generate_quote_number end quote_num end def random_string(size=8) # return a random string end For the test, I simply lookup 3 existing quote numbers, append nil to the end (for a total of 4) ## The test it "should not generate a duplicate quote number" do existing_quote_numbers = Policy.find(:all).map{|p| p.quote_number} [0,3] @policy_service .should_receive (:random_string ).with (:no_args ).exactly(4).times.and_return(existing_quote_numbers.concat([nil])) @policy_service.generate_quote_number end ## The result should not generate a duplicate quote number Mock ''Service::Base'' expected :random_string with (no args) 4 times, but received it once I verified "and_return" is actually returning the array rather than an individual element of the existing_quote_numbers array which makes sense, but what about this? http://rspec.rubyforge.org/svn/branches/dogfood/spec/spec/mocks/mock_spec.rb specify "should use a list of return values for successive calls" do @mock.should_receive(:multi_call).twice.with(:no_args).and_return([8, 12]) @mock.multi_call.should_equal 8 @mock.multi_call.should_equal 12 @mock.__verify end Any feedback on how to properly test this is much appreciated. Thanks, Doug -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20080305/71cfbcb4/attachment-0001.html
I''m having a problems mocking successive return values. I don''t know if I''m doing something wrong or if this is a limitation of rspec mocks. Any ideas of what I may be doing wrong? I''m trying to test the generate_quote_number method. It generates a quote number, looks to see if it is in the db already. If it is, it calls itself to try again. I want to test that it looks in the database for matching numbers until it finds one which does not exist already. ## The code def generate_quote_number quote_num = "MMQ#{self.random_string}-001" if Policy.find(:first, :conditions => ["quote_number = ?", quote_num]) quote_num = generate_quote_number end quote_num end def random_string(size=8) # return a random string end For the test, I simply lookup 3 existing quote numbers, append nil to the end (for a total of 4) ## The test it "should not generate a duplicate quote number" do existing_quote_numbers = Policy.find(:all).map{|p| p.quote_number}[0,3] @policy_service.should_receive(:random_string).with(:no_args).exactly(4).times.and_return(existing_quote_numbers.concat([nil])) @policy_service.generate_quote_number end ## The result should not generate a duplicate quote number Mock ''Service::Base'' expected :random_string with (no args) 4 times, but received it once I verified "and_return" is actually returning the array rather than an individual element of the existing_quote_numbers array which makes sense, but what about this? http://rspec.rubyforge.org/svn/branches/dogfood/spec/spec/mocks/mock_spec.rb specify "should use a list of return values for successive calls" do @mock.should_receive(:multi_call).twice.with(:no_args).and_return([8, 12]) @mock.multi_call.should_equal 8 @mock.multi_call.should_equal 12 @mock.__verify end Any feedback on how to properly test this is much appreciated. Thanks, Doug -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20080305/c36fbd5f/attachment.html
Doug Bryant wrote:> I''m having a problems mocking successive return values. I don''t know > if I''m doing something wrong or if this is a limitation of rspec > mocks. Any ideas of what I may be doing wrong? > > > For the test, I simply lookup 3 existing quote numbers, append nil to > the end (for a total of 4) > ## The test > it "should not generate a duplicate quote number" do > existing_quote_numbers = Policy.find(:all).map{|p| > p.quote_number}[0,3] > > @policy_service.should_receive(:random_string).with(:no_args).exactly(4).times.and_return(existing_quote_numbers.concat([nil])) > @policy_service.generate_quote_number > end >You will need to have one expectation per return. Try this: it "should not generate a duplicate quote number" do #expect Policy.find(:all).map{|p| p.quote_number}[0,3].concat([nil]).each do |existing_quote_number| @policy_service.should_receive(:random_string).with(:no_args).once.and_return(existing_quote_number)) end #when @policy_service.generate_quote_number end -Ben
Thanks Ben. I appreciate it. Doug On Wed, Mar 5, 2008 at 1:25 PM, Ben Mabey <ben at benmabey.com> wrote:> Doug Bryant wrote: > > I''m having a problems mocking successive return values. I don''t know > > if I''m doing something wrong or if this is a limitation of rspec > > mocks. Any ideas of what I may be doing wrong? > > > > > > For the test, I simply lookup 3 existing quote numbers, append nil to > > the end (for a total of 4) > > ## The test > > it "should not generate a duplicate quote number" do > > existing_quote_numbers = Policy.find(:all).map{|p| > > p.quote_number}[0,3] > > > > > @policy_service.should_receive(:random_string).with(:no_args).exactly(4).times.and_return(existing_quote_numbers.concat([nil])) > > @policy_service.generate_quote_number > > end > > > > You will need to have one expectation per return. Try this: > > it "should not generate a duplicate quote number" do > #expect > Policy.find(:all).map{|p| p.quote_number}[0,3].concat([nil]).each do > |existing_quote_number| > > > @policy_service.should_receive(:random_string).with(:no_args).once.and_return(existing_quote_number)) > end > #when > @policy_service.generate_quote_number > end > > > > -Ben > _______________________________________________ > 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/20080305/24144d0d/attachment.html
On Wed, Mar 5, 2008 at 9:30 AM, Doug Bryant <doug+rspecuser at netinlet.com> wrote: @policy_service.should_receive(:random_string).with(:no_args).exactly(4).times.and_return(existing_quote_numbers.concat([nil]))> @policy_service.generate_quote_number > end > > ## The result > should not generate a duplicate quote number > Mock ''Service::Base'' expected :random_string with (no args) 4 times, but > received it once > > I verified "and_return" is actually returning the array rather than an > individual element of the existing_quote_numbers array which makes senseYou need to splat em out: and_return(*existing_quote_numbers.concat([nil])) Pat
On Wed, Mar 5, 2008 at 2:17 PM, Pat Maddox <pergesu at gmail.com> wrote:> > You need to splat em out: > > and_return(*existing_quote_numbers.concat([nil])) > > Pat >Hi, Pat, Just for my own edification and education, if you have a minute, could you explain what this means and why you have to do it? Thanks, -Corey -- http://www.coreyhaines.com The Internet''s Premiere source of information about Corey Haines -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20080305/20670b70/attachment.html
On Wed, Mar 5, 2008 at 12:06 PM, Corey Haines <coreyhaines at gmail.com> wrote:> > On Wed, Mar 5, 2008 at 2:17 PM, Pat Maddox <pergesu at gmail.com> wrote: > > > > > > You need to splat em out: > > > > > > and_return(*existing_quote_numbers.concat([nil])) > > > > Pat > > > > Hi, Pat, > > Just for my own edification and education, if you have a minute, could you > explain what this means and why you have to do it?Basically it takes an array and splits it up. Here''s a little irb session that ought to demonstrate it.>> def foo(val); p val; end=> nil>> a = [1,2,3]=> [1, 2, 3]>> foo(a)[1, 2, 3] => nil>> foo(*a)ArgumentError: wrong number of arguments (3 for 1) from (irb):4:in `foo'' from (irb):4 The method expects one argument. When I pass it an array, everything is fine because it only has one object. However when I splat the array, it splits it up into three distinct objects and tries to pass it in, causing the method to blow up. In RSpec, you specify multiple values to return by passing in multiple objects. An array is just one object, so the mock just returns it. Splat it out and you''ve passed multiple values to and_return, causing it to return them in succession. * is called the splat operator and can be used to collect stuff in addition to splitting stuff up. Just google for "ruby splat operator" to get lots of info. Also you can define #to_splat on any object. Pat
Wow! That is really cool. Thanks for the explanation, Pat. -Corey -------------- next part -------------- An HTML attachment was scrubbed... URL: http://rubyforge.org/pipermail/rspec-users/attachments/20080305/52f09ef4/attachment.html