This post originated from an RSS feed registered with Ruby Buzz
by Jim Weirich.
Original Post: Mock Turtle Soup
Feed Title: { | one, step, back | }
Feed URL: http://onestepback.org/index.cgi/synopsis.rss
Feed Description: Jim Weirich's Blog on Software Development, Ruby, and whatever else sparks his interest.
Mock objects are testing objects that stand in for a real object in a unit
test. They are used to test the interactions between objects.
For example, the other night I was testing some CGI code. To display a page
of HTML, my object under test calls a print_template method on an
object in the CGI framework I am using. It needs to pass in the template
name and a hash table of template values to be substituted in the template.
The test code might look something like this …
def test_error_page
web = CGI::Template.new # Object from the CGI framework
page = ErrorPage.new(web)
page.error_message = "Oops!"
page.render
# test that "Oops!" was properly passed to the template object.
end
The last line of the test wants to validate that the error message was
properly passed to the web template. We could check this by parsing the
HTML output from the CGI::Template, but that is a lot of work (not to
mention error prone as well).
A much better way is to directly test that the parameters are passed to the
CGI framework object correctly. We do that by replacing the CGI framework
object with out own mock object.
Something like this (lines numbered for reference)…
In line 2, the FlexMock.use method creates a mock object and passes it to
the given block. At the end of the block (line 9), FlexMock.use will verify
that all expected calls were actually made to the mock object.
In line 3, we inform the mock web object what methods calls it should
expect by passing the name of the expected method to mock_handle.
Since we are only interested in the print_template call, that is
all we define. The number 1 in the calling sequence tells our mock object
to expect exactly one call.
The mock_handle method also gets a block (still on line 3). This
block is executed whenever print_template is called in our test.
The block object parameters (template_name and hash in
this case) should match the parameters of the print_template
method.
It is the hash argument to print_template that hold our
interest. We need to make sure that the hash table passed to the template
engine correctly defines our error message as "Oops!". We verify
this in line 4.
The rest of the test method just creates an ErrorPage and feeds it the mock
object primed for testing. In line 8 we invoke the render method
that should eventually format our page and call the print_template
method of the mock object.
By using the mock object, we avoid a lot of setup details that would be
required for a real CGI framework object (which in turn might require more
objects with more setup). Using a mock object allows us to concentrate on
the details of what is being tested without constructing an elaborate
framework of live objects merely to support a quick test.
On the other hand, be careful. It is easy to get carried away with mocking
to the point where it is more work to create a web of mock objects than it
is to just create a network of live objects in the first place. When you
start creating mock object that return other mock objects, you should take
one step back and reassess your code base.
There are other Mock objects implementations. The original ruby-mock object is a
bit rigid for my tastes. You need to know exactly what methods are called
and in what order, and that over constrains the solution to your test. The
test-unit-mock
object is much more flexible than ruby-mock (or even FlexMock), it is just
complicated enough that I forget how to use it between the times I need it.
FlexMock seems to fit in that middle of the position where, for me, it does
what I need without extra stuff.