You're definitely testing too much implementation and not enough behavior. Basically, what you want to spec, is that provided some options, when you call a certain method of your form builder, you get a certain html output. At least that's how I would approach the problem.
So I would have something like this: it "produces a correctly formatted FOO input" do html = @builder.foo_text(...) html.should == "<label for='foo'>FOO</label> <input id='foo'....>" end Since testing generated HTML like that sucks, I would proceed to use something like http://github.com/fnando/rspec-hpricot-matchers, and say it "produces a correctly formatted FOO input" do html = @builder.foo_text(...) html.should have_tag("label", :for => "foo") html.should have_tag("input", :id => "foo") end Or something like that. But then if you stop using that question(*args, &block) method, and refactor to a different implementation, specs should continue to pass. -foca On Thu, Jan 28, 2010 at 7:14 PM, Paul Hinze <paul.t.hi...@gmail.com> wrote: > Ashley Moran <ashley.mo...@patchspace.co.uk> on 2010-01-28 at 13:28: >> >> On Jan 28, 2010, at 1:29 pm, Paul Hinze wrote: >> >> > I believe the lack of ability to use this notation comes down to a ruby >> > limitation, but I'm not sure. If that's the case, then we would need a >> > specific argument expectation (along the lines of my suggestion) that >> > executes in a context in which it can call the block. >> >> I can't find a solution, I suspect Ruby 1.8 can't do this, but I'm guessing. >> >> Can I ask why you want to do this though? As another example, it >> would be unusual to spec something like: >> >> @array = [1, 2, 3] >> @array.should_receive(:map).with(block_that_doubles_values) >> >> You'd instead check that the array that came out was [2, 4, 6]. > > I'm trying to spec a large set of what essentially come down to > decorator methods in a Rails FormBuilder extension plugin. What this > boils down to is methods that wrap rails FormBuilder methods, so > `f.text(*args)` ends up calling `f.text_field(*args)` to generate an > <input> tag, but only after it does its own logic and wrapping, which > among a bunch of other things wraps the output in an <li>. > > So the methods run the gamut in complexity from 'f.radio' to > 'f.dependent_collection' to 'f.sigma', but much of the common code is > wrapped up in a method called 'f.question', which does the outer <li> > wrapping, required field detection, label and error display, and a few > other common things required by every control we use in our forms. > > So most of our methods have this basic structure: > > class OurFormBuilder < ActionView::Helpers::FormBuilder > def foo_text(method, options={}) > foo_option = options.delete(:foo_option) > options[:value] ||= 'FOO' > > # some logic, using foo_option somewhere... > > question(method, options) do |remaining_options| > 'FOO -->' + text_field(method, remaining_options) + '<-- FOO' > end > end > end > > I started out with a nice spec for `question`'s behavior and made it all > in a shared group, but because of the number of examples just for > question and the number of methods that call it (so both performance and > complexity), I'm thinking about switching to message expectations in all > of my `foo_text`-style method specs: > > describe 'foo_text' > it 'calls text field with the proper options' do > �...@builder.should_receive(:text_field).with(:some_method, :proper_args) > �...@builder.foo_text(:some_method) > end > it 'yields a wrapped text_field into question' do > # dont test rails text_field > text_field_return = "BOOGA" > �...@builder.stub!(:text_field).and_return(text_field_return) > > expected = "FOO -->" + text_field_return + "<-- FOO" > > �...@builder.should_receive(:question).with(:some_method).with_a_block_yielding(expected) > > �...@builder.foo_text(:some_method, :some => options) > end > it 'properly returns the result of the call to question' do > �...@builder.stub!(:question).and_return('BOOGA') > xhtml = @builder.foo_text(:some_method) > xhtml.should == 'BOOGA' > end > end > > I'd appreciate any feedback that folks might be willing to give. > Particularly I realize the following: > > (a) This might be testing implementation too much (possible) > (b) The architecture of the whole plugin needs a serious refactor to > increase modularity and decouple the components (very likely); a > dash of decent OO design could really help this whole situation, > and it's something I'm planning on tackling down the road > > For now, I'm just trying to push things in the right direction, and I > _think_ the .with_a_block_yielding(value) or .with(block_yielding(value)) > argument verification would help me do that. > > Thanks for your time! > > Paul > _______________________________________________ > 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