[rspec-users] Message expectation that verifies result of passed block

Matt Wynne matt at mattwynne.net
Thu Jan 28 17:45:01 EST 2010


On 28 Jan 2010, at 21:14, Paul Hinze wrote:

> Ashley Moran <ashley.moran at 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)

I'd say so. I would think the most stable seam around which to write  
tests for this is where you call the FormBuilder to make HTML. I would  
not start tinkering around inside it with mocks between inheritance  
layers like that - it's a path that will make it very hard to do any  
refactoring in future.

> (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 at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users

cheers,
Matt

http://mattwynne.net
+447974 430184



More information about the rspec-users mailing list