On Sat, Apr 11, 2009 at 3:59 PM, Brandon Olivares <programmer2...@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@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users