On Sun, Apr 26, 2009 at 9:20 PM, Dan North <tasta...@gmail.com> wrote: > 2009/4/24 Stephen Eley <sfe...@gmail.com> >> >> On Thu, Apr 23, 2009 at 2:19 PM, Fernando Perez <li...@ruby-forum.com> >> wrote: >> >> [...] >> >> # Assume an article with no comments and a params structure >> # have already been set up in before(:each) >> >> it "should make a new comment belonging to the article" do >> post :create, :comment => @my_valid_params >> �...@my_article.should have(1).comment >> end >> >> How clean is that? Now just a couple more specs for *invalid* params >> and for where the method directs to, and you're basically done. > > Amen to that. > >> >> > Mocking and stubbing is starting to get ugly now. >> >> That much is true. You'll notice I didn't mock or stub anything up >> there. I honestly think the controller code by the RSpec scaffold >> generator is the wrong approach; it's specing implementation, not >> behavior. Even worse, it's specing the implementation details of >> *model* code, which shouldn't even be a consideration here. My way >> breaks isolation (it hits the database) but it's a lot simpler and >> focuses on behavior. > > And amen to that too. > > Even within an rspec example I think of each line of code as a Given > (setup), When (event) or Then (outcome). Usually when I see a line doing > more than one of these - say calling a method and verifying its result - I > break it out into separate event and outcome lines. > > The reason for this is that the givens and outcomes can tinker with whatever > they want. They can create mocks, poke around in the database, wire up > models, whatever. The event lines though - the Whens - can only interact > with the object like client code would. In other words they can't know that > an object is a mock, or that a value got into a database because you poked > it there. > > Your example is great. You have an event line that interacts with the > controller through a regular HTTP POST, like a client would, and you verify > that by checking the database via the ActiveRecord model object. There is no > need for a mock here if your example is checking that data ends up in the > database (although that does make it more of an integration test than a > behavioural spec). Because of rails's evil insistence that a "model" is just > a persistence strategy, they are pretty much the same thing. > >> Is it possible to get behavior focus *and* isolation? > > Yes, but it only has value on a per-line-of-code-in-your-spec basis. Your > givens and outcomes shouldn't care about isolation - your events should only > be exercising behaviour that is available in the object you are describing. > > It gets more complicated when a single line of code both exercises behaviour > and does verification. I find breaking these out helps my sanity. > >> I started to >> think about that. And then I realized, in accordance with the "If >> it's hard to spec you're probably doing it wrong" principle, >> that...well, Rails is probably doing it wrong. Controllers in Rails >> are just doing the Wrong Thing. That's why specing them is so >> painful, and why so many of us skip trying.
I've struggled with this bit myself, as I suspect many of us who did TDD before Rails have. RSpec's mocking/stubbing framework just got a contribution that allows you to do this in a controller spec: Thing.stub_chain(:all, :with_some_scope, :perhaps_another). and_return([stub_model(Thing)] This let's you stub a chain of named scopes, for example, in a rails controller. Similarly, with models: member.stub_chain(:addresses, :first, :zip_code) Admittedly, this can result in an excuse for poor design choices. In this example, the first address probably has some meaning that could be exposed through a method like primary_address() or some such. Even in that case, I think that allowing member.stub_chain(:primary_address, :zipcode) would be preferable over adding methods like primary_address_zipcode(). Of course, a little method_missing magic could solve that as well :) I guess it's good to have options. >> >> What's the right way? I'm still pondering. > > Me too! > >> >> Yeah, I'm a smartass. > > Well you seem to be on the right lines to me. > > Cheers, > Dan > > > _______________________________________________ > 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