how could this test pass? I have: class PropertiesController < ApplicationController def show @property = Property.non_existing_method #causes a method missing error end end describe PropertiesController do def mock_property(stubs={}) @mock_property ||= mock_model(Property, stubs) end describe "responding to GET show" do it "should expose the requested property as @property" do Property.should_receive(:non_existing_method).and_return(mock_property) get :show, :id => "37" assigns[:property].should equal(mock_property) end end end SB-MacBook-Pro:test sb$ ruby ./spec/controllers/properties_controller_spec.rb . Finished in 0.134667 seconds 1 example, 0 failures why zero failures? more specifically, why would :non_existing_method return mock_property? and why would the assigns[:property] be equal to mock_property? did I eat some bad mushrooms? Sergio -- Posted via http://www.ruby-forum.com/.
On Sun, Feb 8, 2009 at 7:35 PM, Sergio Bayona <lists at ruby-forum.com> wrote:> how could this test pass? > > I have: > > class PropertiesController < ApplicationController > def show > @property = Property.non_existing_method #causes a method missing > error > end > end > > > describe PropertiesController do > def mock_property(stubs={}) > @mock_property ||= mock_model(Property, stubs) > end > > describe "responding to GET show" do > it "should expose the requested property as @property" do > Property.should_receive(:non_existing_method).and_return(mock_property)* should_receive does not care if the object actually responds to the method - if you tell the object to expect it, it will respond to it * and_return is a declaration of a stub value to return when the object receives the message that it should receive Put that together, and this line says exactly what it looks like it says: The Property class should receive :non_existing_method, and when it does, it should return mock_property to whatever code is calling it. That make any sense now?> get :show, :id => "37" > assigns[:property].should equal(mock_property) > end > end > end > > SB-MacBook-Pro:test sb$ ruby > ./spec/controllers/properties_controller_spec.rb > . > > Finished in 0.134667 seconds > > 1 example, 0 failures > > > why zero failures? more specifically, why would :non_existing_method > return mock_property? and why would the assigns[:property] be equal to > mock_property? did I eat some bad mushrooms? > > Sergio > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >
On Mon, Feb 9, 2009 at 2:35 AM, Sergio Bayona <lists at ruby-forum.com> wrote:> how could this test pass? > > I have: > > class PropertiesController < ApplicationController > def show > @property = Property.non_existing_method #causes a method missing > error > end > end > > > describe PropertiesController do > def mock_property(stubs={}) > @mock_property ||= mock_model(Property, stubs) > end > > describe "responding to GET show" do > it "should expose the requested property as @property" do > Property.should_receive(:non_existing_method).and_return(mock_property) > get :show, :id => "37" > assigns[:property].should equal(mock_property) > end > end > end > > SB-MacBook-Pro:test sb$ ruby > ./spec/controllers/properties_controller_spec.rb > . > > Finished in 0.134667 seconds > > 1 example, 0 failures > > > why zero failures? more specifically, why would :non_existing_method > return mock_property?Because you have stubbed the class method Property#non_existing_method with: Property.should_receive(:non_existing_method).and_return(mock_property) It doesn''t make any difference whether this method is already defined or not. Once the stub is set up, calls to the stubbed method will return what you told it to return.> and why would the assigns[:property] be equal to > mock_property?Because your controller''s #show method assigns @property with the value returned from Property#non_existing_method (which you stubbed).> did I eat some bad mushrooms? >That I don''t know. Why do you think this behaviour is strange/hallucinating? Aslak> Sergio > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >-- Aslak (::)
Sergio Bayona wrote:> how could this test pass? > > I have: > > class PropertiesController < ApplicationController...> why zero failures? more specifically, why would :non_existing_method > return mock_property? and why would the assigns[:property] be equal to > mock_property? did I eat some bad mushrooms? > > SergioAh... Maybe because of this? Property.should_receive(:non_existing_method).and_return(mock_property) -- Posted via http://www.ruby-forum.com/.
2009/2/8 Sergio Bayona <lists at ruby-forum.com>> how could this test pass? > > I have: > > class PropertiesController < ApplicationController > def show > @property = Property.non_existing_method #causes a method missing > error > end > end > > > describe PropertiesController do > def mock_property(stubs={}) > @mock_property ||= mock_model(Property, stubs) > end > > describe "responding to GET show" do > it "should expose the requested property as @property" do > > Property.should_receive(:non_existing_method).and_return(mock_property) > get :show, :id => "37" > assigns[:property].should equal(mock_property) > end > end > end > > SB-MacBook-Pro:test sb$ ruby > ./spec/controllers/properties_controller_spec.rb > . > > Finished in 0.134667 seconds > > 1 example, 0 failures > > > why zero failures? more specifically, why would :non_existing_method > return mock_property? and why would the assigns[:property] be equal to > mock_property?Because that''s what you''re saying with your and_return call above. The and_return method is not part of the expectation: it allows you to specify what value you want to be returned each time the expected message is received. You can find more info at http://rspec.info/documentation/mocks/message_expectations.html. Regards, Mat?as A. Flores> did I eat some bad mushrooms? > > Sergio > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > 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/20090209/7c2d70e4/attachment.html>
On Sun, Feb 8, 2009 at 5:35 PM, Sergio Bayona <lists at ruby-forum.com> wrote:> how could this test pass? > > I have: > > class PropertiesController < ApplicationController > def show > @property = Property.non_existing_method #causes a method missing > error > end > end > > > describe PropertiesController do > def mock_property(stubs={}) > @mock_property ||= mock_model(Property, stubs) > end > > describe "responding to GET show" do > it "should expose the requested property as @property" do > > Property.should_receive(:non_existing_method).and_return(mock_property) > get :show, :id => "37" > assigns[:property].should equal(mock_property) > end > end > end > > SB-MacBook-Pro:test sb$ ruby > ./spec/controllers/properties_controller_spec.rb > . > > Finished in 0.134667 seconds > > 1 example, 0 failures > > > why zero failures? more specifically, why would :non_existing_method > return mock_property? and why would the assigns[:property] be equal to > mock_property? did I eat some bad mushrooms? >That''s just the way this mock library works. It just makes sure it receives a particular message and then returns a certain value in response. It doesn''t actually check to see whether the mocked object responds to that message. Given Ruby''s dynamic nature, that check might not even be valid at the time. Of course, this can be a source of false positives. That''s what you get when you test behavior instead of state. ///ark -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20090208/8b6bd108/attachment.html>
Aslak Helles?y wrote:> On Mon, Feb 9, 2009 at 2:35 AM, Sergio Bayona <lists at ruby-forum.com> > wrote: >> >> assigns[:property].should equal(mock_property) >> 1 example, 0 failures >> >> >> why zero failures? more specifically, why would :non_existing_method >> return mock_property? > > Because you have stubbed the class method Property#non_existing_method > with: > Property.should_receive(:non_existing_method).and_return(mock_property) > > It doesn''t make any difference whether this method is already defined > or not. Once the stub is set up, calls to the stubbed method will > return what you told it to return. > >> and why would the assigns[:property] be equal to >> mock_property? > > Because your controller''s #show method assigns @property with the > value returned from Property#non_existing_method (which you stubbed). > >> did I eat some bad mushrooms? >> > > That I don''t know. Why do you think this behaviour is > strange/hallucinating? > > Aslakah! okay it''s starting to make sense... and the mushroom effect is wearing out. just kidding ;) Thank you guys. By the way I just bought the "Rspec Book" and it''s seems like a great resource. It has encouraged me to learn the framework. Sergio -- Posted via http://www.ruby-forum.com/.
On Sun, Feb 8, 2009 at 8:54 PM, Sergio Bayona <lists at ruby-forum.com> wrote:> Aslak Helles?y wrote: >> On Mon, Feb 9, 2009 at 2:35 AM, Sergio Bayona <lists at ruby-forum.com> >> wrote: >>> >>> assigns[:property].should equal(mock_property) >>> 1 example, 0 failures >>> >>> >>> why zero failures? more specifically, why would :non_existing_method >>> return mock_property? >> >> Because you have stubbed the class method Property#non_existing_method >> with: >> Property.should_receive(:non_existing_method).and_return(mock_property) >> >> It doesn''t make any difference whether this method is already defined >> or not. Once the stub is set up, calls to the stubbed method will >> return what you told it to return. >> >>> and why would the assigns[:property] be equal to >>> mock_property? >> >> Because your controller''s #show method assigns @property with the >> value returned from Property#non_existing_method (which you stubbed). >> >>> did I eat some bad mushrooms? >>> >> >> That I don''t know. Why do you think this behaviour is >> strange/hallucinating? >> >> Aslak > > > ah! okay it''s starting to make sense... and the mushroom effect is > wearing out. just kidding ;) > > Thank you guys. By the way I just bought the "Rspec Book" and it''s seems > like a great resource. It has encouraged me to learn the framework.That''s great news, thanks! If you have any constructive feedback to provide about the book, please do so at: http://www.pragprog.com/titles/achbd/errata http://forums.pragprog.com/forums/95 Cheers, David> > Sergio > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users
On Sun, Feb 8, 2009 at 6:54 PM, Sergio Bayona <lists at ruby-forum.com> wrote:> > On Mon, Feb 9, 2009 at 2:35 AM, Sergio Bayona <lists at ruby-forum.com> > > wrote: > >> > >> assigns[:property].should equal(mock_property) > >> 1 example, 0 failures > >> > >> > >> why zero failures? more specifically, why would :non_existing_method > >> return mock_property? >Dogpile! ///ark -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20090208/a401f56e/attachment-0001.html>
On Sun, Feb 8, 2009 at 6:09 PM, Mat?as Flores <mflores at atlanware.com> wrote:> > You can find more info at http://rspec.info/documentation/mocks/message_expectations.html. >On that page, I found this example of using a computed return value with an expectation: my_mock.should_receive(:msg).with(:numeric, :numeric) once.and_return {|a, b| a + b} I''m not familiar with :numeric. Does it mean what it looks like it means? ///ark
2009/2/9 Mark Wilden <mark at mwilden.com>> On Sun, Feb 8, 2009 at 6:09 PM, Mat?as Flores <mflores at atlanware.com> > wrote: > > > > You can find more info at > http://rspec.info/documentation/mocks/message_expectations.html. > > > > On that page, I found this example of using a computed return value > with an expectation: > > my_mock.should_receive(:msg).with(:numeric, :numeric) once.and_return > {|a, b| a + b} > > I''m not familiar with :numeric. Does it mean what it looks like it means? >That example is a bit outdated. Use of symbols as mock argument constraints such as :numeric, :string, :anything, etc, are deprecated. The expectation above should be replaced with: my_mock.should_receive(:msg).with(an_instance_of(Numeric), an_instance_of(Numeric)).once.and_return {|a, b| a + b} Regards, Mat?as> ///ark > _______________________________________________ > 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/20090209/552f27e4/attachment.html>
On Mon, Feb 9, 2009 at 6:22 AM, Mat?as Flores <mflores at atlanware.com> wrote:> > 2009/2/9 Mark Wilden <mark at mwilden.com> >> >> On Sun, Feb 8, 2009 at 6:09 PM, Mat?as Flores <mflores at atlanware.com> >> wrote: >> > >> > You can find more info at >> > http://rspec.info/documentation/mocks/message_expectations.html. >> > >> >> On that page, I found this example of using a computed return value >> with an expectation: >> >> my_mock.should_receive(:msg).with(:numeric, :numeric) once.and_return >> {|a, b| a + b} >> >> I''m not familiar with :numeric. Does it mean what it looks like it means? > > That example is a bit outdated.And now fixed: http://rspec.info/documentation/mocks/message_expectations.html> Use of symbols as mock argument constraints > such as :numeric, :string, :anything, etc, are deprecated. > > The expectation above should be replaced with: > > my_mock.should_receive(:msg).with(an_instance_of(Numeric), > an_instance_of(Numeric)).once.and_return {|a, b| a + b} > > Regards, > Mat?as > >> >> ///ark >> _______________________________________________ >> 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 >
Mark Wilden wrote:> On Sun, Feb 8, 2009 at 6:54 PM, Sergio Bayona <lists at ruby-forum.com> > wrote: > >> > On Mon, Feb 9, 2009 at 2:35 AM, Sergio Bayona <lists at ruby-forum.com> >> > wrote: >> >> >> >> assigns[:property].should equal(mock_property) >> >> 1 example, 0 failures >> >> >> >> >> >> why zero failures? more specifically, why would :non_existing_method >> >> return mock_property? >> > > Dogpile! > > ///arkEvidently I''m still not fully getting it... why would this not pass? I mean I know why it doesn''t pass. One instance is a mock object and the other is an AR object. But, shouldn''t it return the mock property? There''s just something elemental about Rspec I still don''t get. describe "responding to GET new" do it "should expose a new property as @property" do @account = mock_model(Account) @account.should_receive(:properties) @property = mock_model(Property, :new_record? => false, :errors => []) @account.properties.should_receive(:build).and_return(@property) get :new assigns[:property].should == @property end end def new @property = @account.properties.build respond_to do |format| format.html # new.html.erb format.xml { render :xml => @property } end end ''PropertiesController responding to GET new should expose a new property as @property'' FAILED expected: #<Property:0x1191b84 @name="Property_1002">, got: #<Property id: nil, name: nil, address: nil, city: nil, state: nil, zip: nil, uasap: nil, tax_number: nil, rent_due: nil, units_count: 0, issues_count: 0, account_id: 1, created_at: nil, updated_at: nil> (using ==) -- Posted via http://www.ruby-forum.com/.
On Mon, Feb 9, 2009 at 10:18 PM, Sergio Bayona <lists at ruby-forum.com> wrote:> Mark Wilden wrote: >> On Sun, Feb 8, 2009 at 6:54 PM, Sergio Bayona <lists at ruby-forum.com> >> wrote: >> >>> > On Mon, Feb 9, 2009 at 2:35 AM, Sergio Bayona <lists at ruby-forum.com> >>> > wrote: >>> >> >>> >> assigns[:property].should equal(mock_property) >>> >> 1 example, 0 failures >>> >> >>> >> >>> >> why zero failures? more specifically, why would :non_existing_method >>> >> return mock_property? >>> >> >> Dogpile! >> >> ///ark > > Evidently I''m still not fully getting it... why would this not pass? I > mean I know why it doesn''t pass. One instance is a mock object and the > other is an AR object. But, shouldn''t it return the mock property? > There''s just something elemental about Rspec I still don''t get. > > > > describe "responding to GET new" do > > it "should expose a new property as @property" do > @account = mock_model(Account) > @account.should_receive(:properties) > @property = mock_model(Property, :new_record? => false, :errors => > []) > @account.properties.should_receive(:build).and_return(@property) > get :new > assigns[:property].should == @property > end > > end > > def new > @property = @account.properties.build > > respond_to do |format| > format.html # new.html.erb > format.xml { render :xml => @property } > end > end > > > > ''PropertiesController responding to GET new should expose a new property > as @property'' FAILED > expected: #<Property:0x1191b84 @name="Property_1002">, > got: #<Property id: nil, name: nil, address: nil, city: nil, state: > nil, zip: nil, uasap: nil, tax_number: nil, rent_due: nil, units_count: > 0, issues_count: 0, account_id: 1, created_at: nil, updated_at: nil> > (using ==) > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users >Hi in your new method, where does @account come from? Is it loaded through some kind of before_filter, or as part of the authentication framework? Anyway, once you''ve built up your mock expectations you now need to inject the mock into the code. You do this by stubbing the code that loads up the @account object - typically you''re just doing an Account.find call somewhere. Note also that you need to specify that account returns something when properties is called - you need to hook up the association proxy. it "should expose a new property as @property" do @account = mock_model(Account) Account.should_receive(:find).with("1").and_return @account @account.stub!(:properties).and_return mock(''properties proxy'') @property = mock_model(Property, :new_record? => false, :errors => []) @account.properties.should_receive(:build).and_return(@property) get :new assigns[:property].should == @property end end additionally I would only have two expectations (should_receive) and would loosen the rest by just stubbing: it "should expose a new property as @property" do # arrange @account = mock_model(Account, :properties => mock(''properties proxy'')) @property = mock_model(Property, :new_record? => false, :errors => []) @account.properties.stub!(:build).and_return(@property) # sanity check Account.should_receive(:find).with("1").and_return @account # act get :new # assert assigns[:property].should == @property end end I like to minimize the number of expectations(/assertions) that appear in the example. Doing so clearly communicates the important behavior. If the final expectation passes, you can infer that it''s doing the right thing with the model because that''s the only way to get to your mock @property. Finally I threw in an Account.should_receive("1") because you need to inject the mock account somehow. That does the trick, and it also serves as a sanity check for the contract between controller and model - Account.find is the entry point to the model in this action. Does that make sense? Pat
Sergio, Responding to your original question. This issue has bugged me a lot in the past 1 year. And apparently, a lot of other people. As already explained, the spec should indeed pass. But there should be a failure somewhere because your code will obviously not work. Synthesis is a great tool for checking this stuff automatically. Read a bit about it here (http://nutrun.com/weblog/synthesized-testing-a- primer/) and here (http://github.com/gmalamid/synthesis/tree/master) Pradeep
On Mon, Feb 9, 2009 at 10:18 PM, Sergio Bayona <lists at ruby-forum.com> wrote:> describe "responding to GET new" do > > it "should expose a new property as @property" do > @account = mock_model(Account) > @account.should_receive(:properties) > @property = mock_model(Property, :new_record? => false, :errors => > []) > @account.properties.should_receive(:build).and_return(@property) > get :new > assigns[:property].should == @property > end > > endAnother thing is that instance variables shouldn''t be used unless necessary. As a rule of thumb, things should have as limited a scope as possible. Prefer class variables to global variables, instance variables to class variables, and local variables to instance variables. Some reasons are 1) to better communicate your intent, 2) to limit the places you have to look to see where a variable is being changed, and 3) to limit the amount of code that might depend on the variable. ///ark
Pat Maddox wrote:> On Mon, Feb 9, 2009 at 10:18 PM, Sergio Bayona <lists at ruby-forum.com> > wrote: >>>> >> >> other is an AR object. But, shouldn''t it return the mock property? >> []) >> respond_to do |format| >> got: #<Property id: nil, name: nil, address: nil, city: nil, state: >> nil, zip: nil, uasap: nil, tax_number: nil, rent_due: nil, units_count: >> 0, issues_count: 0, account_id: 1, created_at: nil, updated_at: nil> >> (using ==) >> -- >> Posted via http://www.ruby-forum.com/. >> _______________________________________________ >> rspec-users mailing list >> rspec-users at rubyforge.org >> http://rubyforge.org/mailman/listinfo/rspec-users >> > > Hi in your new method, where does @account come from? Is it loaded > through some kind of before_filter, or as part of the authentication > framework? > > Anyway, once you''ve built up your mock expectations you now need to > inject the mock into the code. You do this by stubbing the code that > loads up the @account object - typically you''re just doing an > Account.find call somewhere. Note also that you need to specify that > account returns something when properties is called - you need to hook > up the association proxy. > > it "should expose a new property as @property" do > @account = mock_model(Account) > Account.should_receive(:find).with("1").and_return @account > @account.stub!(:properties).and_return mock(''properties proxy'') > @property = mock_model(Property, :new_record? => false, :errors => > []) > @account.properties.should_receive(:build).and_return(@property) > get :new > assigns[:property].should == @property > end > end > > additionally I would only have two expectations (should_receive) and > would loosen the rest by just stubbing: > > it "should expose a new property as @property" do > # arrange > @account = mock_model(Account, :properties => mock(''properties > proxy'')) > @property = mock_model(Property, :new_record? => false, :errors => > []) > @account.properties.stub!(:build).and_return(@property) > > # sanity check > Account.should_receive(:find).with("1").and_return @account > > # act > get :new > > # assert > assigns[:property].should == @property > end > end > > I like to minimize the number of expectations(/assertions) that appear > in the example. Doing so clearly communicates the important behavior. > If the final expectation passes, you can infer that it''s doing the > right thing with the model because that''s the only way to get to your > mock @property. Finally I threw in an Account.should_receive("1") > because you need to inject the mock account somehow. That does the > trick, and it also serves as a sanity check for the contract between > controller and model - Account.find is the entry point to the model in > this action. > > Does that make sense? > > PatThanks Pat. You''re right. Account comes from a before_filter that triggers this: def current_account @account ||= Account.find_by_subdomain(account_subdomain) end I have stubbed the code on the spec_helper.rb to do that as: def current_account(account) @controller.stub!(:current_account).and_return(@account = account ? accounts(account) : nil) #should return account fixture end on the property spec now I have: describe PropertiesController do fixtures :accounts, :properties, :users before(:each) do current_account(:default) login_as(:default) end describe "responding to GET new" do it "should expose a new property as @property" do property = mock_model(Property, :new_record? => false, :errors => []) @account.properties.should_receive(:build).and_return(property) get :new assigns[:property].should == property end end end but now the controller complains that @account is nil: The error occurred while evaluating nil.properties /www/rentcloud2/app/controllers/properties_controller.rb:23:in `new'' I thought by stubbing the current_account code and returning @account, that''d be available to the application. -- Posted via http://www.ruby-forum.com/.