Hi all - I've been keeping an eye on this thread and I've just been too busy with holiday travel and book writing to participate as I would like.
I'm just going to lay out some thoughts in one fell swoop rather than going back through and finding all the quotes. Hope that works for you. First - "mock roles, not objects" - that comes from a paper of the same name written by Steve Freeman, Nat Pryce, Tim Mackinnon, Joe Walnes who I believe were all working for ThoughtWorks, London in 2004. They describe using mocks as part of a process to stay focused on one object at a time and let mock objects help you to discover the interfaces of the current object's collaborators. My read is that they do not make a distinction between domain objects and service objects, though they do make a distinction between "your" objects (which you should mock) and "everyone else's" (which you should not). My own approach is largely derived from this document, and I'd recommend that everyone participating in this thread give it a read: http://www.jmock.org/oopsla2004.pdf. I think one place that we tend to get stuck on, and this is true of TDD in general, not just mocks, is that mocks need not be a permanent part of any example. Before I encountered Rails it was common for me to use mocks in a test and then replace them with the mocked object later. This decision would depend on many factors, and I can't say that I sought to eliminate mocks when I could, but there were times when it just made more sense to use a real object once it came to be. Rails is a different beast because we don't really have a sense of 3 layers with lots of little objects in each. Instead we have what amount to 3 giant objects with lots of behavior in each and even shared state across layers. For me, this rationalizes isolating things with mocks and stubs (which is counter to the recommendation in the oopsla paper referenced above). Because the framework itself provides virtually no isolation, the spec suite must if you want isolation. Zach's idea of branch nodes and leaf nodes really speaks to me. I don't remember where I read this, but I long ago learned that an ideal OO operation consists of a chain of messages over any number of objects, culminating at a boundary object (what Zach is calling a leaf node). It should also favor commands over queries (Tell Don't Ask), so while all of the getters we get for free on our AR model objects is convenient, from an OO perspective it's a giant encapsulation-sieve (again, more reason to isolate things w/ stubs/mocks in tests). You might find http://www.holub.com/publications/notes_and_slides/Everything.You.Know.is.Wrong.pdf in regards to this. In this paper, Holub suggests that getters are evil and we should use importers and exporters instead of exposing getters/setters. If we were to re-engineer rails to satisfy this, instead of this in a controller: def index @model = Model.find(params[:id]) render :template => "some_template" end you might see something more like this: def index Model.export(params[:id]).to(some_template) end Here Model would still do a query, but it becomes internal to the Model (class) object. Then it passes some_template to the model and says "export yourself", at which point the model starts calling methods like name=self.name. The fact that the recipient of the export is a view is unknown to the model, so there is no conceptual binding between model and view. Ah, just think of how easy THAT would be to mock, and when things are easy to mock, it means that it is easy to swap out components in the chain of events, thus using run-time conditions to alter the path of a given operation through different objects. There is much, much more to say, but this is all I have time to contribute right now. Cheers, and Happy New Year to all! David _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users