Forum: RSpec rspec macro style

Posted by Lenny Marks (Guest)
on 2011-08-25 20:28
(Received via mailing list)
One of the things that always annoys me when I write/use typical macros 
in my specs is how the backtrace from failures don't include the caller 
of the macro. Not a huge deal because the example name can be used to 
track it down, but I lose the ability to do things like click on the 
line from the backtrace in my IDE(I use RubyMine). I find that feature 
to be a nice time saver. I've never heard any mention of this bothering 
anybody so maybe I'm just being pedantic but tweaking things so that the 
actual example implementation is yielded by the caller seems like a 
better style to me because it solves that problem. Just curious if 
anybody else has any thoughts one way or the other. I've been leaning 
toward the latter when possible.

Full example at:
https://gist.github.com/1169172

ex. When the example below fails, line 17 is significant

     5  describe Email do
     6    describe '.normalize', ' should strip email down to core 
address' do
     7      def self.normalized(original, options)
     8        it %{normalizes '#{original}' as '#{options[:should_be]}'} 
do
     9          Email.normalize(original).should == options[:should_be]
    10        end
    11      end
    .....
    16      describe 'it strips whitespace' do
    17        normalized('   joe@somewhere.com', :should_be => 
'joe@somewhere.com')
    18      end

Failures:

  1) Email.normalize should strip email down to core address it strips 
whitespace normalizes '   joe@somewhere.com' as 'joe@somewhere.com'
     Failure/Error: Email.normalize(original).should == 
options[:should_be]
       expected: "joe@somewhere.com"
            got: "   joe@somewhere.com" (using ==)
     # org/jruby/RubyProc.java:268:in `call'
     # ./spec/lib/email_spec.rb:9:in `normalized'
     # org/jruby/RubyKernel.java:2028:in `instance_eval'

Compare to this where the significant lines are present in the backtrace

describe Email do
     6    describe '.normalize', ' should strip email down to core 
address' do
     7      def self.normalized(original, &blk)
     8        describe "'#{original}'" do
     9          subject { Email.normalize(original) }
    10          it { instance_eval(&blk) }
    11        end
    12      end
    ......
    17      describe 'it strips whitespace' do
    18        normalized('   joe@somewhere.com') { should == 
'joe@somewhere.com' }
    19      end

Failures:

  1) Email.normalize should strip email down to core address it strips 
whitespace '   joe@somewhere.com'
     Failure/Error: normalized('   joe@somewhere.com') { should == 
'joe@somewhere.com' }
       expected: "joe@somewhere.com"
            got: "   joe@somewhere.com" (using ==)
     # org/jruby/RubyProc.java:268:in `call'
     # ./spec/lib/email_spec.rb:18:in `(root)'
     # org/jruby/RubyKernel.java:2028:in `instance_eval'
     # ./spec/lib/email_spec.rb:10:in `normalized'
     # org/jruby/RubyKernel.java:2028:in `instance_eval'
     ...


-lenny
Posted by David Chelimsky (Guest)
on 2011-08-26 08:20
(Received via mailing list)
On Aug 25, 2011, at 11:40 AM, Lenny Marks wrote:

>     8        it %{normalizes '#{original}' as '#{options[:should_be]}'} do
>  1) Email.normalize should strip email down to core address it strips whitespace 
normalizes '   joe@somewhere.com' as 'joe@somewhere.com'
>     Failure/Error: Email.normalize(original).should == options[:should_be]
>       expected: "joe@somewhere.com"
>            got: "   joe@somewhere.com" (using ==)
>     # org/jruby/RubyProc.java:268:in `call'
>     # ./spec/lib/email_spec.rb:9:in `normalized'
>     # org/jruby/RubyKernel.java:2028:in `instance_eval'

If you run this with the --backtrace flag, you should see line 17 as 
well.

>    ......
>     # org/jruby/RubyProc.java:268:in `call'
>     # ./spec/lib/email_spec.rb:18:in `(root)'
>     # org/jruby/RubyKernel.java:2028:in `instance_eval'
>     # ./spec/lib/email_spec.rb:10:in `normalized'
>     # org/jruby/RubyKernel.java:2028:in `instance_eval'

Interesting that that happens. I'm not clear on why. Regardless, this 
macro appraoch creates a lot of distance between the reader and the code 
that is being specified. Personally, I find this much easier to read:

describe Email do
  describe "#normalize" do
    it "strips whitespace" do
      Email.normalize('   joe@somewhere.com').should 
eq('joe@somewhere.com')
    end
  end
end

... and it would give exactly the spec output and failure message that I 
want.

Don't get me wrong - I'm all for sharing code where it provides a 
benefit that outweighs the loss of proximity, but I would typically do 
that with custom matchers, shared examples or simple helper methods (at 
the example level rather than the group level).

FWIW,
David
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.