Brian Candler [mailto:B.Candler / pobox.com] wrote:

> On Sat, Aug 02, 2003 at 06:13:55PM +0900, Nathaniel Talbott wrote:
> > I find myself doing the following in tests a lot:
> > 
> >   some_external_object = Object.new
> >   def some_external_object.some_method
> >     ... do some stuff ...
> >   end
> > 
> > Is there a way to do that more concisely? Perhaps to eliminate the 
> > separate Object.new?

<snip>

> You say you do this in tests a lot (test/unit?)

But of course ;-)


> Can you give a more concrete example?

  require 'test/unit'
  
  class TC_ParamPrettifier < Test::Unit::TestCase
    def test_prettify
      cgi = Object.new
      def cgi.params
        {'param1' => 'value1', 'param2' => 'value2'}
      end
      
      assert_equal((<<EXP).chomp, ParamPrettifier.new(cgi).prettify)
  param1
    value1
  param2
    value2
  EXP
    end
  end
  
  class ParamPrettifier #Contrived, I know
    def initialize(cgi)
      @cgi = cgi
    end
    
    def prettify
      @cgi.params.collect do |key, value|
        "#{key}\n  #{value}"
      end.join("\n")
    end
  end

The basic idea is that I have a class (like CGI) that's a pain to set up
and/or use, and I want to mock (sham, fake, stub) it. So I create a regular
old object (ROO... MOO? FOO? GOO? Sorry...) and take advantage of Ruby's
wonderful dynamic nature to just add the methods that I need for that test.
I'm just looking for ways to make it easier and/or more concise to do this.


> > Also, is there a way to let the methods be more like closures, i.e.:
> > 
> >   a = "stuff"
> > 
> >   some_external_object = Object.new
> >   def some_external_object.some_method
> >     a #from external scope
> >   end
> > 
> >   assert_equal(a, method_under_test(some_external_object))
> > 
> > That would make it even more powerful.
> 
> If you find yourself needing that, usually the 'right' 
> solution is to make 'a' into an instance variable (@a) of some object.

If you take my example above and imagine that you want to define and use the
hash returned by the mock CGI object in the test method as well, you can see
why this is advantageous. What I've done in the past is to add an accessor
method for such data, but I'm looking for something more concise.


> You *can* achieve what you want, though, using define_method 
> which converts a proc object into a method. The example at 
> the bottom of http://www.rubygarden.org/ruby?SingletonTutorial
> might help.

Ah! This does exactly what I want... I'll have to grab that method, stick it
in a module, and include it in my tests. Thanks for the pointer.


> I also valuely remember that 1.8 might let you pass a block to 'def'.

Really? I don't remember that...

Thanks,


Nathaniel

<:((><