Forum: Ruby on Rails dynamic mock object anyone?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
4a021d3e4528fb8ab78ef7fc4b6822cc?d=identicon&s=25 Bao Lee (burninglegion)
on 2006-04-20 06:19
Hi guys, got this problem with creating such a thing... hope anyone
could help..

the problem:

ok, now i have this mock object that would simulate a external rpc call.
eg

require 'models/xmlrpc_agent'

class XmlrpcAgent

  def create(params)
    200
  end
end

but the value of the value returned is fixed. which is quite hard for me
to test the controller when different values are returned from the rpc
call.... is there a way to make the number returned dynamic?? Dynamic in
the sense that i can pre-define the returned number in the functional
test case to simulate the different kind of situation that might
arise....

-burninglegion
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2006-04-20 07:34
(Received via mailing list)
On Apr 19, 2006, at 9:19 PM, bao lee wrote:

>
> class XmlrpcAgent
>
>   def create(params)
>     200
>   end
> end

This is a stub, not a mock.

> but the value of the value returned is fixed. which is quite hard
> for me
> to test the controller when different values are returned from the rpc
> call.... is there a way to make the number returned dynamic??
> Dynamic in
> the sense that i can pre-define the returned number in the functional
> test case to simulate the different kind of situation that might
> arise....

I use the following pattern when I use stubs, taking advantage of
Ruby's open classes.  My flickr interface use open-uri to do its
work, so I inject my own open that will be called before Kernel's.  I
record the passed URIs and give the positional response.  This makes
it easy to verify the method DTRT.

class Flickr

   attr_accessor :responses, :uris

   def open(uri)
     @uris << uri
     yield StringIO.new(@responses.shift)
   end

end

class FlickrTest < Test::Unit::TestCase

   #...

   def test_find_email
     @flickr.responses << <<-EOF
<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
         <user id="50178138@N00" nsid="50178138@N00">
                 <username>drbrain</username>
         </user>
</rsp>
     EOF

     nsid = @flickr.find_email :find_email => 'drbrain@segment7.net'

     assert_equal 1, @flickr.uris.length
     assert_equal 'http://flickr.com/services/rest/?
api_key=API_KEY&find_email=dr
brain%40segment7.net&method=flickr.people.findByEmail',
                  @flickr.uris.first

     assert_equal '50178138@N00', nsid
   end

end

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
4a021d3e4528fb8ab78ef7fc4b6822cc?d=identicon&s=25 Bao Lee (burninglegion)
on 2006-04-20 09:04
Hi eric,

sory for the confusion which i first came upon... the ruby on rails book
didnt tell me much about stubs and also the differences between the
2....

ok so after reading thorugh the code i got a rough idea about it but it
seems to be a bit complicated....btw does this apply to functional test
also??
15619be638a3ae3d6f86a4995c6484c1?d=identicon&s=25 Dee Zsombor (Guest)
on 2006-04-20 14:12
(Received via mailing list)
Use FlexMock, quite simple and powerful.
91eb330fb36d1e03c856574dfb77d2bc?d=identicon&s=25 Thibaut Barrère (Guest)
on 2006-04-20 14:25
(Received via mailing list)
>
> Use FlexMock, quite simple and powerful.
>

Thanks for the pointer
6c27f78ab0eee78732ae54e8b8718b84?d=identicon&s=25 David Felstead (Guest)
on 2006-04-20 14:34
(Received via mailing list)
I wrote an article about selectively overriding methods in particular
instances of objects for testing - I called them "Partial Mock
Objects".

http://karmiccoding.com/articles/2006/03/11/under-...

Cheers,

-David Felstead
4a021d3e4528fb8ab78ef7fc4b6822cc?d=identicon&s=25 Bao Lee (burninglegion)
on 2006-04-21 03:14
David Felstead wrote:
> I wrote an article about selectively overriding methods in particular
> instances of objects for testing - I called them "Partial Mock
> Objects".
>
> 
http://karmiccoding.com/articles/2006/03/11/under-...
>
> Cheers,
>
> -David Felstead

yeah i have seen that post... great post...
4a021d3e4528fb8ab78ef7fc4b6822cc?d=identicon&s=25 Bao Lee (burninglegion)
on 2006-04-21 03:47
bao lee wrote:
> David Felstead wrote:
>> I wrote an article about selectively overriding methods in particular
>> instances of objects for testing - I called them "Partial Mock
>> Objects".
>>
>> 
http://karmiccoding.com/articles/2006/03/11/under-...
>>
>> Cheers,
>>
>> -David Felstead
>
> yeah i have seen that post... great post...

btw i think that that post only works with instances of objects... issit
possible the change the class itself rather than instance of the class?

cos my problem is the stub that i used is to replace something in the
controller algorithm and i cant change it within the controller... so it
does not work when i try
override_method(XmlrpcAgent,:create) { 502 }
where XmlrpcAgent is the class name and :create is the name of the
function....

is there any tweaks to the code you have done that could allow that to
happen??

thanks for you help
4a021d3e4528fb8ab78ef7fc4b6822cc?d=identicon&s=25 Bao Lee (burninglegion)
on 2006-04-21 04:06
bao lee wrote:


hey David Felstead , i think i have found what i wanted... from your
code :

def override_method(obj,method_name,&block)
    #klass = class <<obj; self; end
    #klass.send( :undef_method , method_name )
    #klass.send( :define_method, method_name, block)
    obj.send(:undef_method,method_name)
    obj.send(:define_method,method_name,block)
end

the one commented is the your original code, the one uncommented is the
one i wrote.... this way the class method is changed completely and my
testing went as smooth as it can get!!! thanks for the enlightenment
provided!!
4a021d3e4528fb8ab78ef7fc4b6822cc?d=identicon&s=25 Bao Lee (burninglegion)
on 2006-04-21 05:33
bao lee wrote:

> def override_method(obj,method_name,&block)
>     #klass = class <<obj; self; end
>     #klass.send( :undef_method , method_name )
>     #klass.send( :define_method, method_name, block)
>     obj.send(:undef_method,method_name)
>     obj.send(:define_method,method_name,block)
> end

ok... i found a disadvantage when doing this way....that is when writing
my tests, when i called this override method.. the next test that used
the overrided class method will not be revert back automatically....eg.
for the class in test/mock/test :
class XmlrpcAgent

  def create(params)
    200
  end
end

in test_controller :
if i called override_method(XmlrpcAgent,:create){ 502 } in one of my
test case

then the next test case that used XmlrpcAgent class will now return 502
rather than 200....
so the next test case that need to use XmlrpcAgent will have to override
the method to its own use.... well a bit of hard coding here... but i
think that would be the best solution i could think of currently...
6c27f78ab0eee78732ae54e8b8718b84?d=identicon&s=25 David Felstead (Guest)
on 2006-04-21 23:51
(Received via mailing list)
Hey there,

Yeah, the aim of the code provided is to only override the method
specified in a particular instance of the object.  If you want to do
it for the entire class, what you have there will work, but as you've
seen it will carry through for the subsequent tests.  If you want to
revert it back, you would have to put something in your test's
'teardown' method to bring it back...

Have a look at the 'alias_method' call in the Ruby API - instead of
using 'undefine_method' you could alias the method being overriden to
another same ("#{method_name}_old", for example) and in the teardown
you could alias it back.  I _think_ that would work.

Cheers!

-David Felstead
4a021d3e4528fb8ab78ef7fc4b6822cc?d=identicon&s=25 Bao Lee (burninglegion)
on 2006-04-24 03:47
David Felstead wrote:
> Hey there,
>
> Yeah, the aim of the code provided is to only override the method
> specified in a particular instance of the object.  If you want to do
> it for the entire class, what you have there will work, but as you've
> seen it will carry through for the subsequent tests.  If you want to
> revert it back, you would have to put something in your test's
> 'teardown' method to bring it back...
>
> Have a look at the 'alias_method' call in the Ruby API - instead of
> using 'undefine_method' you could alias the method being overriden to
> another same ("#{method_name}_old", for example) and in the teardown
> you could alias it back.  I _think_ that would work.
>
> Cheers!
>
> -David Felstead

hmmm... interesting... ok i will go and take a look about that and post
any updates i have...
thanks !!
This topic is locked and can not be replied to.