Tom -- perfect. That's exactly the kind of explanation I was looking
for, and now I can go and deal with these changes with a worry-free mind.
I find it too easy to forget that a class's public methods are, in fact,
an API (particularly when there are no libraries involved) and need to
be tested as such.
Thanks for taking the time to write this up; I may thumbtack it to the
wall for a while.
dwh
Tom Stuart wrote:
On 25 Aug 2009, at 18:12, Denis Haskin wrote:
The key expectation in this example is:
@discount.should_not be_available(@order)
But I changed the implementation of Discount#available? so that it
calls Order#num_products instead of Order#line_items. My examples
now fail.
Why am I having trouble getting comfortable with this?
Your specification describes the interaction of Discount with the rest
of the system; the idea of mocking is to nail down how a Discount
object behaves in isolation from all of the other objects it interacts
with. (And then, at a higher level, you have integration tests to
check that all of the individual behaviours you've specified play
nicely together.) If you change the nature of these interactions, for
example by getting Discount to ask Order for a number instead of for a
collection of line items, then you're essentially changing the API
between different parts of your application so your specs will and
should fail.
This is exactly the right amount of brittleness for the level the
specs operate at. Your integration tests should still pass, indicating
that the system as a whole still works, while your specs fail,
indicating that the interactions between objects are not what you
specified. Some of the time it does feel like you're fixing up
unnecessary breakage but it's important for the specs to be able to
reveal failures at this fine-grained level because these sorts of API
changes aren't always made deliberately, especially when you're doing
big refactorings.
Note that your specs are only "brittle" in the sense that changes in
the contracts between collaborating objects ("Discount expects Order
to be able to return a collection of line items" changing to "Discount
expects Order to be able to say how many products it consists of")
require matching changes in those objects' specifications. You can
change the implementation of methods on Discount as much as you like
-- by replacing poor algorithms with more efficient ones, for example
-- and the specs won't necessarily break unless your changes affect
the interactions between Discount and "the outside world" of other
objects.
Cheers,
-Tom
_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users
_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users