James Moore
2007-Feb-06 17:45 UTC
[mocha-developer] Using any_instance with Rails to make sure the right thing is saved?
I''d like to test that an object with the correct attributes is saved, something like: def test_create_without_existing_suite this = self w = Annotation.any_instance.expects(:save).with do |x| this.assert_equal ''fnord'', some_way_get_the_name_of_the_receiver_of_save true end w.returns true end But the object is created inside the method being tested (in this case, a test of a Rails controller''s ''create'' method), so I don''t think there''s a way to just mock the method on the particular object. Is there a way to get the target of the mocked method from inside any_instance? Or am I going about this the wrong way? Is there a way to be notified when new instances of a class are created, and then do something like automatically mock some of their methods? - James Moore
James Mead
2007-Feb-06 18:57 UTC
[mocha-developer] Using any_instance with Rails to make sure the right thing is saved?
On 06/02/07, James Moore <jamesthepiper at gmail.com> wrote:> > I''d like to test that an object with the correct attributes is saved, > something like: > > def test_create_without_existing_suite > this = self > w = Annotation.any_instance.expects(:save).with do |x| > this.assert_equal ''fnord'', > some_way_get_the_name_of_the_receiver_of_save > true > end > w.returns true > end > > But the object is created inside the method being tested (in this case, a > test of a Rails controller''s ''create'' method), so > I don''t think there''s a way to just mock the method on the particular > object. > > Is there a way to get the target of the mocked method from inside > any_instance? > > Or am I going about this the wrong way? Is there a way to be notified > when > new instances of a class are created, and then do something like > automatically mock some of their methods? >You can stub the ''new'' or ''create'' methods of a class and return a mock object. So you''d have something along these lines in your test... annotation = mock(''annotation'') annotation.expects(:update_attributes).with(:name => ''wibble'').returns(true) Annotation.stubs(:new).returns(new_annotation) post :create, :name => ''wibble'' -- James. http://blog.floehopper.org
James Moore
2007-Feb-07 20:31 UTC
[mocha-developer] Using any_instance with Rails to make sure the right thing is saved?
On 2/6/07, James Mead <jamesmead44 at gmail.com> wrote:> > So you''d have something along these lines in your test... > > annotation = mock(''annotation'') > annotation.expects(:update_attributes).with(:name => > ''wibble'').returns(true)Is there a standard way to get information from the ''with'' bit to the ''return'' bit? It''d be useful to be able to build the return object based on information from the original call to ''new''. I did it by stashing away the values in the ''with'' block to be used later on in the Proc used by return(): # Set up S2TestSuite so it creates the # mocks we''ve just defined newargs = nil mck = S2TestSuite.stubs(:new).with do |*args| newargs = HashWithIndifferentAccess.new.merge!(args.first) true end objs = [foosuite, barsuite] generator = lambda do result = objs.shift result.attributes = newargs # #new handles arguments differently; it''ll # take an id and turn it into an object. # #attributes= doesn''t do that. if i = newargs[:s2_test_path_id] result.s2_test_path = S2TestPath.find(i.to_i) end result end mck.returns generator But that seems goofy. Is there a) either a better way to pass around the values from #with to #returns, or b) am I just misusing mocks, and I should always specify all the values? - James Moore
James Mead
2007-Feb-08 11:11 UTC
[mocha-developer] Using any_instance with Rails to make sure the right thing is saved?
On 07/02/07, James Moore <jamesthepiper at gmail.com> wrote:> > Is there a standard way to get information from the ''with'' bit to the > ''return'' bit?No. Intentionally not. It''d be useful to be able to build the return object based on> information from the original call to ''new''. I did it by stashing away > the > values in the ''with'' block to be used later on in the Proc used by > return():If you really want to do that, you''d be better off with a traditional Rails "mock" object i.e. an alternative class definition in the "test/mocks" directory. These are what Martin Fowler terms Fake Objects (see http://www.martinfowler.com/articles/mocksArentStubs.html#TheDifferenceBetweenMocksAndStubs ). But that seems goofy. Is there a) either a better way to pass around the> values from #with to #returns, or b) am I just misusing mocks, and > I should always specify all the values? >I think you get much clearer tests if you explicitly specify the return values in each scenario. -- James. http://blog.floehopper.org