[rspec-users] Mocking: brittle specs and tight coupling?

Brandon Olivares programmer2188 at gmail.com
Sat Apr 11 19:57:56 EDT 2009


Pat,

Thank you very much for the link, and dependency injection explanation. That
helps a lot. I like your blog, too.

Brandon

> -----Original Message-----
> From: rspec-users-bounces at rubyforge.org [mailto:rspec-users-
> bounces at rubyforge.org] On Behalf Of Pat Maddox
> Sent: Saturday, April 11, 2009 7:25 PM
> To: rspec-users
> Subject: Re: [rspec-users] Mocking: brittle specs and tight coupling?
> 
> On Sat, Apr 11, 2009 at 3:59 PM, Brandon Olivares
> <programmer2188 at gmail.com> wrote:
> > Hi,
> >
> > I've read of complaints that mocking can make the specs very brittle,
> in
> > that if the method is changed at all, it will break the specs, even
> if the
> > behavior remains the same. Do you find this to be the case? How do
> you deal
> > with this if so?
> 
> http://patmaddox.com/blog/you-probably-dont-get-mocks
> 
> 
> > Also, when I used to do TDD in PHP, well there wasn't the ability to
> modify
> > the class on the fly like in Ruby, so you actually had to do
> dependency
> > injection, but people generally looked at this as a good thing, for
> loose
> > coupling. So if a controller method for instance used a User model,
> then it
> > would be preferred to get that instance from somewhere, either
> passing it to
> > the method itself or calling another method to instantiate it.
> >
> > I notice this isn't a concern in RSpec or in Ruby in general. Do you
> view
> > this differently, or what is the preferred way to deal with
> dependencies? Is
> > it fine just to do:
> >
> > User.should_receive(:new).and_return(User.new)
> >
> > Just as a very simple example?
> 
> I have an example of this in my Legacy Rails talk and say it's the
> sort of thing that would make a Java programmer run for the fucking
> hills.  That's not entirely true because there are a couple mock
> frameworks that do let you do that, but in general they prefer to
> avoid it because it requires bytecode manipulation.
> 
> Ruby is much more flexible and gives us a couple ways of injecting
> dependencies.  You've got traditional DI:
> 
> class Order
>   def calculate_tax(calculator)
>     calculator.calculate total, us_state
>   end
> end
> 
> You've got traditional DI + default args
> 
> class Order
>   def calculate_tax(calculator=TaxCalculator.new)
>     calculator.calculate total, us_state
>   end
> end
> 
> You can partially mock on the target object:
> 
> class Order
>   def calculate_tax
>     calculator.calculate total, us_state
>   end
> 
>   def calculator
>     TaxCalculator
>   end
> end
> 
> order = Order.new
> order.stub!(:calculator).and_return(mock('calculator', :calculate =>
> 1.25))
> 
> or you can use partial mocks somewhere inside of the target object,
> like you showed.
> 
> The pattern you showed is popular because often you won't ever want to
> pass in a different object.  In your UsersController you're only ever
> going to deal with the User class as a repository, and if you change
> it then it's a fairly big change and you don't mind updating your
> tests.
> 
> I find that you can use mocks to express the intent of the class well.
>  Don't use constructor/setter/method dependency injection if you don't
> need it...accept a bit tighter coupling and use partial mocking if all
> you're trying to do is isolate behaviors.
> 
> Pat
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users



More information about the rspec-users mailing list