BDD and mocking objects

Brian H. discussed BDD [1] in a recent post, which piqued my
interest enough to check out RSpec. I used his idea and went through
the first chapter of Refactoring to learn the rspec ropes.

The most interesting stuff is the specs for Customer, but they’re kind
of long, so I’m going to show a less interesting spec.

context “A new rental” do
setup do
@movie = Movie.new(“New Movie”, Movie::REGULAR)
@rental = Rental.new(@movie, 3)
end

specify “should have a movie and rental length” do
@rental.movie.should_be @movie
@rental.days_rented.should_be 3
end
end

I’m wondering if I should be using a mock instead of creating a new
Movie object in setup. This is a trivial example and perhaps it would
be unnecessary, but I want to know if I “get it.” I’m testing a
Rental’s behavior, so I really don’t care about how a Movie behaves.
As long as my Rental gets an object that behaves the same way a movie
does, it should be happy. In this case, I don’t care about a Movie’s
title or code, so I could pass in a nil object if I wanted to. Would
I want to mock the @movie then? Doesn’t matter much in this
particular case, but assume that one of my Rental methods relied on a
method or two of Movie.

Thanks for any input.

Pat

[1] Is test driven development for newbies? - Rails - Ruby-Forum

I say it does matter. Behavior driven development, in particular,
emphasizes testing the way that objects interact. As such, it should
be tested that the Rental class is treating the Movie class properly.
Think of it this way. What if you decided there should be another
type of object that has a similar interface to a Movie object? You
don’t want your Rental tests to be locked to the Movie class since
you want to be able to pass in the other kind of object as well. The
only way to test that is with mock objects. Other reasons for mocking
could include an incomplete or buggy implementation of the Movie
class and better specification of what the roles and responsibilities
of each object are in the program.

  • Jake McArthur

Thanks for the reply Jake. Very good points, and in fact they
basically opened my eyes to a problem that I run into when doing TDD.
If I were to write this system from scratch, focusing on behavior, my
process would go something like this:

  1. Decide to write the Rental class
  2. Realize that Rental depends on Movie
  3. Write the Movie class
  4. Write the Rental class

Again, this is a trivial example, so perhaps the problem here is
non-obvious (to others, I have a feeling you can see it immediately).
At this point I don’t care about a Movie, I only care about a Rental
and its behavior. The way I’ve done things though requires me to
write the Movie class before I even begin working on the Rental’s
behavior. First of all that sidetracks me for a bit while I write
Movie and its tests, and in general I think it leads to me writing
more tightly coupled code.

It seems obvious to me now that when writing a unit test, I should
mock out any relationships, so basically any object that’s not the one
I’m explicitly testing. I’m sure there are exceptions, but does that
seem like a good guideline to follow?

Pat

Yes, I would say that is a good guideline in general. For the record,
I am not a BDD guru by any means, though I have been using BDD
techniques for some time now when using TDD. I have been using RSpec
for roughly a month now, I think.

  • Jake McArthur

I’ve been doing lots of reading this afternoon, and came across a few
comments that leave me with more questions.

Dave A. said in a podcast that RSpec doesn’t take the place of
functional or integration tests.
Martin F. wrote that you must use coarse grained acceptance tests.

I simply don’t know what functional, integration, and acceptance tests
are, and how they differ from unit tests. Where can I find some info
on why I should use them, and how to use them effectively?

Pat

On May 15, 2006, at 3:42 PM, Pat M. wrote:

The way I’ve done things though requires me to write the Movie
class before I even begin working on the Rental’s behavior. First
of all that sidetracks me for a bit while I write Movie and its
tests, and in general I think it leads to me writing more tightly
coupled code.

How does it make your code more coupled?

It seems obvious to me now that when writing a unit test, I should
mock out any relationships, so basically any object that’s not the one
I’m explicitly testing. I’m sure there are exceptions, but does that
seem like a good guideline to follow?

I typically only stub methods, typically overriding superclass
methods in a subclass.

For example, I’ll be using open-uri (which overrides Kernel#open) in
my implementation then add a MyClass#open stub that allows me to
provide the open behavior that open-uri gives. I’ve done the same
with #system and #`.

For me, mocks feel like a lot of typing for something I can achieve
more simply by exploiting Ruby’s dynamic language features.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On May 15, 2006, at 4:33 PM, Pat M. wrote:

I’ve been doing lots of reading this afternoon, and came across a few
comments that leave me with more questions.

Dave A. said in a podcast that RSpec doesn’t take the place of
functional or integration tests.

http://c2.com/cgi/wiki?FunctionalTest

http://c2.com/cgi/wiki?IntegrationTest

Martin F. wrote that you must use coarse grained acceptance tests.

http://c2.com/cgi/wiki?AcceptanceTest

I simply don’t know what functional, integration, and acceptance tests
are, and how they differ from unit tests. Where can I find some info
on why I should use them, and how to use them effectively?

The c2 wiki has descriptions from the best minds in the business.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com