From: Jacob Fugal Date: 2006-05-13T00:45:02+09:00 Subject: Re: Unit testing with mock objects On 5/11/06, Dido Sevilla wrote: > class Foo > def initialize(x, y, &block) > if block_given? > dobjs = block.call > @domain_obj1 = dobjs[:domain_obj1] > @domain_obj2 = dobjs[:domain_obj2] > else > @domain_obj1 = DomainObj1.new > @domain_obj2 = DomainObj2.new > end > end > > so that in my testing code I can do the following: > > FlexMock.use("domain_obj1") do |dobj1| > FlexMock.use("domain_obj2").do |dobj2| > f = Foo.new(x, y) { {:domain_obj1 => dobj1, :domain_obj2 => dobj2 } } > end > end I like the "trailing option hash" "pattern" (used loosely). It's pretty close to what you've got, but syntactlcally a little nicer. I'd do it like this for your demonstrated class: class Foo DEFAULTS = { :domain_obj1 => DomainObj1, :domain_obj2 => DomainObj2 } def initialize(x, y, options={}) options.merge!(DEFAULTS) @domain_obj1 = options[:domain_obj1] @domain_obj2 = options[:domain_obj2] @domain_obj1 = @domain_obj1.new if Class === @domain_obj1 @domain_obj2 = @domain_obj2.new if Class === @domain_obj2 end end I use the classes in the DEFAULTS array so that each instance of Foo can have it's own DomainObj1 (in the default case), rather than having a reference to the same object that was instantiated when the hash was created. The "x = x.new if Class === x" "pattern" (again, loosely using the P word) is also useful in that you can pass in a MockClass as well, rather than an instantiated object, if you want. Example usage: # passing mock objects FlexMock.use("domain_obj1") do |dobj1| FlexMock.use("domain_obj2").do |dobj2| f = Foo.new(x, y, :domain_obj1 => dobj1, :domain_obj2 => dobj2) end end --OR-- # passing mock classes f = Foo.new(x, y, :domain_obj1 => MockDomainObj1, :domain_obj2 => MockDomainObj2) --OR-- # normal, non-test usage, should look same as before: f = Foo.new(x, y) How's that look? Jacob Fugal