Nick Hoffman wrote: > On 2008-08-27, at 15:25, Mark Wilden wrote: >> The other thing I would say is that mocking and stubbing are powerful >> tools that you should add to your arsenal as soon as possible. I've >> had several coworkers who resisted using them, only to finally >> achieve that "aha!" moment later. Your tests get easier to write, and >> they're less brittle to change. > > G'day Mark. I was re-reading this thread and noticed this paragraph of > yours. I've been using RSpec and BDD for about 2 months now, and love it. > > However, I'm not a fan of mocking and stubbing, primarily for two > reasons: > 1) I believe that specs should test behaviour, rather than a > behaviour's implementation. > 2) Using mocks and stubs causes your specs and implementation to be > tightly coupled, which often forces you to modify your specs if > changes occur in the implementation. I'm completely with Zach on this subject, so I won't repeat what he has stated. I will however point out that many people who avoid using mocks simply based on the "test the behaviour not the implementation" argument fail to realize that the same argument applies just as much to state-based testing as it does to interaction-based testing (mocking.) Coupling a test to the implementation is much more subtle than using mocks to predefine collaborator interactions.
Consider this glaringly stupid example in which an ambitious first-time BDDer writes the first spec for a Stack class: describe Stack do describe "#push" do it "should add an item" do stack = Stack.new stack.push(5) stack.items.should == [5] end end end To get this spec to pass they quickly churn out the following code, and all is green: class Stack attr_accessor :items def initialize @items = [] end def push(object) @items.push object end end The encapsulation of the Stack is clearly broken by adding the 'attr_accessor :items' call. Not just that, but the spec is now tied to how the stack implements it's behaviour. (In fact no relevant behaviour was even being speced in the first place, it was all internal structure!) If the Stack decides to use some other container or method to implement the behavior then all the specs would need to be changed. This was a painfully simple example, but the best I could come up with off the top of my head. I'm certainly not suggesting that using mocks here would be better, I'm just illustrating what I believe is meant by "test the behaviour not the implementation". As programs grow in size these sort of issues tend to creep up more subtlety and such coupling isn't so obvious. I have noticed that with a purely state-based approach the creation and testing of objects at the unit level seems to increase in difficultly and require more setup as the complexity of a system increases. Mocks not only allow you to discover your interface but also help in breaking dependencies and keeping your unit level specs focused on just that object's responsibility. I should point out however that with every spec I have that uses mocking I always have an application level test (a story) that executes the same code with the full stack in motion. I'm also constantly trying to find a good balance between state and interaction based testing in my projects. I think that balance is different from project to project, team to team, and developer to developer. With all that said, I think mocking is a fantastic tool to have in your tool kit that can help alleviate a lot of the pain associated with testing and, as Zach explained, is a great tool to discover your design. Wow, sorry for the long-winded reply... that was not my intention when I began to write. :) As Mark pointed out a good article on the matter is Martin Fowler's: http://www.martinfowler.com/articles/mocksArentStubs.html If you read that article would recommend that you follow it up with this one to get another perspective: http://nat.truemesh.com/archives/000342.html -Ben http://www.benmabey.com _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users