# \[ANN\] Mockery initial release (yet another dynamic mock object generator)

**URL:** <https://rubytalk.org/t/ann-mockery-initial-release-yet-another-dynamic-mock-object-generator/20266>\
**Category:** ruby-talk\
**Created:** [19 August 2005 00:12 UTC](https://rubytalk.org/t/ann-mockery-initial-release-yet-another-dynamic-mock-object-generator/20266 "2005-08-19T00:12:08Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Gary\_Shea](https://avatars.discourse-cdn.com/v4/letter/g/779978/32.png) [@Gary\_Shea](https://rubytalk.org/u/Gary_Shea)\
**Post date:** [19 August 2005 00:12 UTC](https://rubytalk.org/t/ann-mockery-initial-release-yet-another-dynamic-mock-object-generator/20266/1 "2005-08-19T00:12:08Z")

</div>

Ruby is a really easy language to write mocks in, and it took  
thousands of lines of test-first code before I finally got tired of  
typing unit-test code like:

&nbsp;&nbsp;x\_class = Class.new(Some::Klass)  
&nbsp;&nbsp;x\_class.class\_eval {  
&nbsp;&nbsp;&nbsp;&nbsp;attr\_reader :blah  
&nbsp;&nbsp;&nbsp;&nbsp;attr\_writer :ret\_val  
&nbsp;&nbsp;&nbsp;&nbsp;def doit(blah)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@blah = blah  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return @ret\_val  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;}  
&nbsp;&nbsp;x = x\_class.new  
&nbsp;&nbsp;ret\_val = Object.new  
&nbsp;&nbsp;x.ret\_val = ret\_val

&nbsp;&nbsp;rv = x.please\_call\_doit(blah)

&nbsp;&nbsp;assert\_equal(blah, x.blah)  
&nbsp;&nbsp;assert\_equal(ret\_val, rv)

There's probably one of these mock objects for every 5-10 lines of my  
program code, and that adds up to a LOT of typing.

Mockery ([http://rubyforge.org/projects/mockery](http://rubyforge.org/projects/mockery)) is a Ruby version of the  
kind of dynamic mock generator that is commonplace in Java. The Java  
versions tend to do a lousy job mocking classes as opposed to  
interfaces, but we don't have that problem in Ruby (not only are there  
no interfaces, but dynamic class modification is SO easy it's just not  
an issue).

A first draft of the above example using Mockery looks like:

&nbsp;&nbsp;ctl = Mockery::Controller.new(Some::Klass)  
&nbsp;&nbsp;ctl.record do |x|  
&nbsp;&nbsp;&nbsp;&nbsp;x.doit('blah')  
&nbsp;&nbsp;end  
&nbsp;&nbsp;ctl.try do |x|  
&nbsp;&nbsp;&nbsp;&nbsp;x.please\_call\_doit('blah')  
&nbsp;&nbsp;end  
&nbsp;&nbsp;assert\_equal(true, ctl.validate, ctl.error\_report)

This code will detect if the call to #please\_call\_doit really  
calls #doit with the correct argument, exactly one time. #doit need not  
actually exist in Some::Klass -- because it's mentioned in the #record  
block, it will be mocked in the #try block.

You may be thinking that the above test fails to handle the return value  
that the hand-coded example checks. Mockery can do that too. Each time  
a call is made to a recording object (arguments to the #record block), a  
call object is returned. The call object's #return\_value= method may be  
used to set a desired return value:

&nbsp;&nbsp;ctl = Mockery::Controller.new(Some::Klass)  
&nbsp;&nbsp;ctl.record do |x|  
&nbsp;&nbsp;&nbsp;&nbsp;call = x.doit(blah)  
&nbsp;&nbsp;&nbsp;&nbsp;call.return\_value = 'blork'  
&nbsp;&nbsp;end  
&nbsp;&nbsp;ctl.try do |x|  
&nbsp;&nbsp;&nbsp;&nbsp;rv = x.please\_call\_doit(blah)  
&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal('blork', rv)  
&nbsp;&nbsp;end  
&nbsp;&nbsp;assert\_equal(true, ctl.validate, ctl.error\_report)

which fully captures the test done in the coded-by-hand version. The  
lines-of-code count is not vastly different, but the potential for error  
is, as is the amount of thought that goes into the test. I find working  
with Mockery much faster.

Finally, an arbitrary number of classes to mock may be handed to the  
Mockery::Controller#new, each of which will be provided with a recorder  
argument in the #record block, and a mock in the #try block.

This is a first release, so it's far short of perfect. I have tentative  
plans for a number of improvements, and I'm open to suggestions. I'm  
especially open to patches 🙂

The biggest weakness of Mockery at the moment is that it does not have a  
clue about mocking methods that use a block. Let me catch my breath  
before tackling that one 😉

Regards,

&nbsp;&nbsp;Gary Shea

---

<div class="post-metadata">

**Author:** ![Pit](https://avatars.discourse-cdn.com/v4/letter/p/f14d63/32.png) [@Pit](https://rubytalk.org/u/Pit)\
**Post date:** [19 August 2005 06:59 UTC](https://rubytalk.org/t/ann-mockery-initial-release-yet-another-dynamic-mock-object-generator/20266/2 "2005-08-19T06:59:55Z")

</div>

Gary Shea schrieb:

> Mockery ([http://rubyforge.org/projects/mockery\](http://rubyforge.org/projects/mockery%5C)) is a Ruby version of the  
> kind of dynamic mock generator that is commonplace in Java. The Java  
> versions tend to do a lousy job mocking classes as opposed to  
> interfaces, but we don't have that problem in Ruby (not only are there  
> no interfaces, but dynamic class modification is SO easy it's just not  
> an issue).
> 
> A first draft of the above example using Mockery looks like:
> 
> &nbsp;&nbsp;ctl = Mockery::Controller.new(Some::Klass)  
> &nbsp;&nbsp;ctl.record do |x|  
> &nbsp;&nbsp;&nbsp;&nbsp;x.doit('blah')  
> &nbsp;&nbsp;end  
> &nbsp;&nbsp;ctl.try do |x|  
> &nbsp;&nbsp;&nbsp;&nbsp;x.please\_call\_doit('blah')  
> &nbsp;&nbsp;end  
> &nbsp;&nbsp;assert\_equal(true, ctl.validate, ctl.error\_report)

Nice work! I will try it if I need mocks in my unit tests. One first question: couldn't you put the last assert into the #try method? Something like

&nbsp;&nbsp;&nbsp;def try  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...  
&nbsp;&nbsp;&nbsp;ensure  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal(true, validate, error\_report)  
&nbsp;&nbsp;&nbsp;end

Regards,  
Pit

---

<div class="post-metadata">

**Author:** ![Gary\_Shea](https://avatars.discourse-cdn.com/v4/letter/g/779978/32.png) [@Gary\_Shea](https://rubytalk.org/u/Gary_Shea)\
**Post date:** [19 August 2005 14:16 UTC](https://rubytalk.org/t/ann-mockery-initial-release-yet-another-dynamic-mock-object-generator/20266/3 "2005-08-19T14:16:43Z")

</div>

I didn't even know you could do that, very slick. The only problem is  
that the idea of the #validate and #error\_report methods is to make #try  
independent of the choice of test framework. So we could do what you're  
saying, but we would have to create a new method:

&nbsp;&nbsp;def test\_unit\_try  
&nbsp;&nbsp;&nbsp;&nbsp;...  
&nbsp;&nbsp;ensure  
&nbsp;&nbsp;&nbsp;&nbsp;assert(validate, error\_report)  
&nbsp;&nbsp;end

and the module that defines that method would have to  
&nbsp;&nbsp;require 'test/unit'  
which means a built-in dependency on Test::Unit.

Still, it \_would\_ be convenient to not have to do the assert manually.  
A dumb-and-obvious way would be to have a subclass  
Mockery::TestUnitController of Mockery::Controller that just wraps #try  
as above. Unless I think of or hear a better idea I'll do that for the  
next release.

Thanks!

&nbsp;&nbsp;&nbsp;&nbsp;Gary

> **···**
>
> On Fri, 2005-08-19 at 15:59 +0900, Pit Capitain wrote:
> 
> > Gary Shea schrieb:  
> > \> Mockery ([http://rubyforge.org/projects/mockery\](http://rubyforge.org/projects/mockery%5C)) is a Ruby version of the  
> > \> kind of dynamic mock generator that is commonplace in Java. The Java  
> > \> versions tend to do a lousy job mocking classes as opposed to  
> > \> interfaces, but we don't have that problem in Ruby (not only are there  
> > \> no interfaces, but dynamic class modification is SO easy it's just not  
> > \> an issue).  
> > \>  
> > \> A first draft of the above example using Mockery looks like:  
> > \>  
> > \> ctl = Mockery::Controller.new(Some::Klass)  
> > \> ctl.record do |x|  
> > \> x.doit('blah')  
> > \> end  
> > \> ctl.try do |x|  
> > \> x.please\_call\_doit('blah')  
> > \> end  
> > \> assert\_equal(true, ctl.validate, ctl.error\_report)
> > 
> > Nice work! I will try it if I need mocks in my unit tests. One first  
> > question: couldn't you put the last assert into the #try method?  
> > Something like
> > 
> > &nbsp;&nbsp;&nbsp;def try  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...  
> > &nbsp;&nbsp;&nbsp;ensure  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert\_equal(true, validate, error\_report)  
> > &nbsp;&nbsp;&nbsp;end
> > 
> > Regards,  
> > Pit
