On 8/24/07, David Green <[EMAIL PROTECTED]> wrote: > > hypothetical question for all you BDD experts: > > I want to make sure that a :list action always returns widgets in > alphabetical order. There's at least 2 ways of doing this: > > it "should fetch items in alphabetical order" do > Widget.should_receive(:find).with(:order => "name ASC") > get :list > end > > it "should fetch items in alphabetical order" do > [:red, :green, :blue].each {|x| Widget.create(:name => x) } > get :list > assigns[:widgets].first.name.should == 'blue' > assigns[:widgets].last.name.should == 'red' > end > > with the first method, I get to mock the important calls and stub the rest, > but the example is very closely tied to the implementation. If I change from > Widget.find to Widget.find_alphabetically then the example breaks (assuming > find_alphabetically() doesn't use AR::Base.find) > > with the second method, I'm testing the behaviour more than how it's > implemented. I don't care what the action does as long as it gives me an > array of widgets sorted alphabetically, but I spend more time setting things > up and worrying about model validations. In addition, the specs are tied to > a db. > > so which is the better method, and is there another way i havn't considered > that gives me the best of both worlds?
It depends on how high you have your magnifying glass set. Really! Here's how I'd get there: In an integration test, which I use as ... well ... integration tests (i.e. pretty close to end to end - just no browser, so the javascript can't get tested), I'd have something akin to the second example, except that the creates would be done through a controller. This would be in place before I ever started working on individual objects. Then I'd develop the view, followed by the controller, followed by the model. Typically, in my experience, that would result in something like (not executing these so please pardon any potential bugs): describe "/widgets/index" do it "should display a list of widgets" do assigns[:widgets] = [ mock_model(Widget, :name => 'foo'), mock_model(Widget, :name => 'bar') ] render '/widgets/index' response.should have_tag('ul') do with_tag('li', 'foo') with_tag('li', 'bar') end end end describe WidgetController, 'responding to GET /widgets' do it "should assign a list of widgets" do Widget.should_receive(:find_alphabetically).and_return(list = []) get :index assigns[:widgets].should == [] end end describe Widget, "class" do it "should provide a list of widgets sorted alphabetically" do Widget.should_receive(:find).with(:order => "name ASC") Widget.find_alphabetically end end You're correct that the refactoring requires you to change the object-level examples, and that is something that would be nice to avoid. But also keep in mind that in java and C# people refactor things like that all the time without batting an eye, because the tools make it a one-step activity. Refactoring is changing the design of your *system* without changing its behaviour. That doesn't really fly all the way down to the object level 100% of the time. WDYT? David > > -- > View this message in context: > http://www.nabble.com/testing-behaviour-or-testing-code--tf4322619.html#a12309322 > Sent from the rspec-users mailing list archive at Nabble.com. > > _______________________________________________ > 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