Forum: Ruby BDD and mocking objects

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2006-05-16 00:11
(Received via mailing list)
Brian Hughes 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] http://www.ruby-forum.com/topic/65640#77053
49ab3ce5a4922b4747d1d6f330784629?d=identicon&s=25 Jake McArthur (Guest)
on 2006-05-16 00:26
(Received via mailing list)
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
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2006-05-16 00:45
(Received via mailing list)
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
49ab3ce5a4922b4747d1d6f330784629?d=identicon&s=25 Jake McArthur (Guest)
on 2006-05-16 01:19
(Received via mailing list)
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
42172acdf3c6046f84d644cb0b94642c?d=identicon&s=25 Pat Maddox (pergesu)
on 2006-05-16 01:34
(Received via mailing list)
I've been doing lots of reading this afternoon, and came across a few
comments that leave me with more questions.

Dave Astels said in a podcast that RSpec doesn't take the place of
functional or integration tests.
Martin Fowler 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
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2006-05-16 20:39
(Received via mailing list)
On May 15, 2006, at 3:42 PM, Pat Maddox 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 Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
58479f76374a3ba3c69b9804163f39f4?d=identicon&s=25 Eric Hodel (Guest)
on 2006-05-16 20:42
(Received via mailing list)
On May 15, 2006, at 4:33 PM, Pat Maddox wrote:

> I've been doing lots of reading this afternoon, and came across a few
> comments that leave me with more questions.
>
> Dave Astels 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 Fowler 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 Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com
This topic is locked and can not be replied to.