# Unit testing with mock objects

**URL:** <https://www.ruby-forum.com/t/unit-testing-with-mock-objects/60309>\
**Category:** Ruby\
**Created:** [May 11, 2006, 11:59pm UTC](https://www.ruby-forum.com/t/unit-testing-with-mock-objects/60309 "2006-05-11T23:59:29Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dido\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/b3f665/32.png) [@Dido\_S](https://www.ruby-forum.com/u/Dido_S)\
**Post date:** [May 11, 2006, 11:59pm UTC](https://www.ruby-forum.com/t/unit-testing-with-mock-objects/60309/1 "2006-05-11T23:59:29Z")

</div>

I’ve been writing an extensive set of unit tests for a bunch of code  
that I’ve been developing over the past couple of years to improve its  
maintainability and have in the process needed to make more than a few  
mock objects to encapsulate functionality like databases, web  
services, distributed objects, and peripherals to which the program  
interfaces. I’ve been wondering what is the best way to refactor these  
kinds of classes so that it becomes easy to inject mock objects where  
these domain objects are required. What I’ve been doing so far is to  
attach a block to the initialize method that, when specified, is  
called to instantiate these mock objects, e.g.:

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

but this hardly feels like the “right” way to do it. It feels like  
such a kludge. I know I could write factory methods to create my  
domain objects and then reopen the class at testing time and rewrite  
the factory methods to return the mock objects, but then it’s not  
exactly clear how I could feed these rewritten factory methods with  
mock objects instantiated as above, from within the test. I could  
rewrite the initialization method to accept instances of my domain  
objects instead so that at test time I could just feed it with my mock  
objects, but that would also require me to rewrite all the code that  
uses instances of the class in question as well, and that’s not such a  
good idea to do everywhere. Any suggestions?

---

<div class="post-metadata">

**Author:** ![Dido\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/b3f665/32.png) [@Dido\_S](https://www.ruby-forum.com/u/Dido_S)\
**Post date:** [May 12, 2006, 5:46pm UTC](https://www.ruby-forum.com/t/unit-testing-with-mock-objects/60309/2 "2006-05-12T17:46:15Z")

</div>

On 5/11/06, Dido S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> 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 F.

---

<div class="post-metadata">

**Author:** ![Dido\_S](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/b3f665/32.png) [@Dido\_S](https://www.ruby-forum.com/u/Dido_S)\
**Post date:** [May 12, 2006, 5:49pm UTC](https://www.ruby-forum.com/t/unit-testing-with-mock-objects/60309/3 "2006-05-12T17:49:27Z")

</div>

On 5/12/06, Jacob F. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> ```
> 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

Shame on me for posting without testing… I got my merge backwards,  
it should be:

options = DEFAULTS.merge(options)

Since the values in the argument, not receiver, take precedence if  
both have a key.

Jacob F.
