On 28 Jan 2010, at 21:43, Nicolás Sanguinetti wrote:

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.

What he said.


-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

cheers,
Matt

http://mattwynne.net
+447974 430184

_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to