<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Inter-sections.net : Category rspec, everything about rspec</title>
    <link>http://inter-sections.net/category/rspec.rss</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Business, Technology, Life</description>
    <item>
      <title>Array matcher</title>
      <description>&lt;p&gt;Here&amp;#8217;s a lovely little snippet that shows the reasons why Ruby is such a nice language to work with. It&amp;#8217;s to do with matching at least one of a series of items in RSpec.&lt;/p&gt;

&lt;h3&gt;Step 1: First, it was simple&lt;/h3&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Then&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;user $email should receive an email with his confirmation link&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;email&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
  mail &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ActionMailer&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;deliveries&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;last
  user &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;find_by_email&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;email&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  mail&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;body&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;match&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_regexp string_regexp_classic string_regexp_classic_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;user&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;confirmation_code&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mail&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;body&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;match&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_regexp string_regexp_classic string_regexp_classic_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;user&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;id&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This is my simple matcher that I started with&amp;#8230; The world was simple, and this worked fine. But then, something happened. The world started sending more than a single email in one Story, and so the need for matching multiple emails was born.&lt;/p&gt;

&lt;h3&gt;Step 2: Then, it was easy, but messy&lt;/h3&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Then&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;user $email should receive an email with his confirmation link&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;email&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
  matches &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;
  &lt;span class="support support_class support_class_ruby"&gt;ActionMailer&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;deliveries&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;mail&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
    user &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;find_by_email&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;email&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    matches &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;+=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;mail&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;body&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;match&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_regexp string_regexp_classic string_regexp_classic_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;user&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;confirmation_code&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mail&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;body&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;match&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_regexp string_regexp_classic string_regexp_classic_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;user&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;id&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;))&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
  matches&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;==&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This works. It works well. It works fine. But, it&amp;#8217;s ugly. It&amp;#8217;s not readable. It&amp;#8217;s not RSpec-like, and it stands out like a sore thumb in the middle of my step matchers. I have Ruby to thank for the fact that fugly hacks like this stand out and beg to be rewritten in a neater way. Other languages, such as PHP, do not have this quality, and so hacks remain untouched for ages and ages.&lt;/p&gt;

&lt;p&gt;I could not let things rest in this state. Ugliness like that &lt;em&gt;must&lt;/em&gt; be removed. Trying to match any one of an array of items is one of those things that are likely to be repeated a few times, so I decided to extract that out. This is where another one of Ruby&amp;#8217;s qualities came forth, and made it child&amp;#8217;s play to extract this concept and stick it where it belongs - in Enumerable (but, I hasten to add, only when running specs&amp;#8230;).&lt;/p&gt;

&lt;h3&gt;Step 3: Then, it was simple again&lt;/h3&gt;

&lt;p&gt;Enter my latest addition to /stories/helper.rb:&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_environment-variable meta_environment-variable_ruby"&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ENV&lt;/span&gt;[&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;RAILS_ENV&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;]&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;test&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;File&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;expand_path&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;File&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;dirname&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_language variable_language_ruby"&gt;__FILE__&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby"&gt;+&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;/../config/environment&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;spec/rails/story_adapter&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="meta meta_module meta_module_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_module keyword_control_module_ruby"&gt;module&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_module entity_name_type_module_ruby"&gt;Enumerable&lt;/span&gt;&lt;/span&gt;
&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;  &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; my_array.should_match_at_least_one { |item| item.match(/abc/) &amp;amp;&amp;amp; item.match(/def/) }
&lt;/span&gt;  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;at_least_one_should&lt;/span&gt;&lt;/span&gt;
    matches &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;0&lt;/span&gt;
    &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;item&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
      matches &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;+=&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby"&gt;yield&lt;/span&gt; item
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
    matches&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should &lt;span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Which means that the step matcher can now been reduced to the reasonably elegant and expressive:&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Then&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;user $email should receive an email with his confirmation link&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;email&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
  user &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;find_by_email&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;email&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="support support_class support_class_ruby"&gt;ActionMailer&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Base&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;deliveries&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;at_least_one_should &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;mail&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;
    mail&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;body&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;match&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_regexp string_regexp_classic string_regexp_classic_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;user&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;confirmation_code&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby"&gt;&amp;amp;&amp;amp;&lt;/span&gt; mail&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;body&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;match&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_regexp string_regexp_classic string_regexp_classic_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;user&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;id&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;You might be tempted to point out that I could probably use String#include? instead of String#match, since I do not care about the actual matching, only about the presence&amp;#8230; and you&amp;#8217;d be right. But, like an &lt;a href="http://www.thepersianruggalleries.com/guide.htm"&gt;imperfectly perfect persian rug&lt;/a&gt;, I&amp;#8217;m happy with my code like this.&lt;/p&gt;</description>
      <pubDate>Mon, 26 Nov 2007 20:04:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:01ea1b0d-5932-4906-ae9e-dbb281e41783</guid>
      <comments>http://inter-sections.net/2007/11/26/array-matcher#comments</comments>
      <category>Technology</category>
      <category>Ruby / Rails</category>
      <category>RSpec</category>
      <trackback:ping>http://inter-sections.net/trackbacks?article_id=array-matcher&amp;day=26&amp;month=11&amp;year=2007</trackback:ping>
      <link>http://inter-sections.net/2007/11/26/array-matcher</link>
    </item>
    <item>
      <title>What to test and specify, and where to do it</title>
      <description>&lt;p&gt;So I&amp;#8217;ve been struggling a bit with my &lt;a href="http://www.inter-sections.net/2007/10/03/the-difference-between-tdd-and-bdd/"&gt;specifications approach&lt;/a&gt; lately. Well, only until I found out about the new &lt;a href="http://evang.eli.st/blog/2007/9/1/user-stories-with-rspec-s-story-runner"&gt;Story Runner functionality&lt;/a&gt; in &lt;a href="http://rspec.rubyforge.org/"&gt;rspec&lt;/a&gt;. That&amp;#8217;s resolved a number of things, by providing a powerful tool to prepare integration tests (in the form of &lt;a href="http://dannorth.net/whats-in-a-story"&gt;User Stories&lt;/a&gt;). From the look of things, it seems like many developers like myself have been lingering in the limbo of no-integration-tests-land, simply because rspec lacked the capability, Test::unit feels unclean, and the full-on rspec-with-&lt;a href="http://wtr.rubyforge.org/"&gt;watir&lt;/a&gt;-or-&lt;a href="http://www.openqa.org/selenium/"&gt;selenium&lt;/a&gt; seems just too large a step when you don&amp;#8217;t even have any integration tests.&lt;/p&gt;

&lt;p&gt;Apart from this obvious benefit, the new Story functionality has allowed me to give some more thought to something that&amp;#8217;s been bothering me. Namely, &amp;#8220;What do you test/specify&amp;#8221;, and where do you do it. One of the salient issues linked to this is how to specify validations. Hang in there for a potential answer as we go through this article (as always, comments are most welcome).&lt;/p&gt;

&lt;h3&gt;What&amp;#8217;s in an app?&lt;/h3&gt;

&lt;p&gt;That&amp;#8217;s a key question when determining what to test and how. We&amp;#8217;re looking at rails apps, here, so the basic model is MVC. So is this what&amp;#8217;s in an app?&lt;/p&gt;

&lt;p&gt;&lt;img src="/files/2007/10/mvc-diagram-1.png" /&gt;&lt;/p&gt;

&lt;p&gt;This is the basic model of a Rails app. However, from the perspective of deciding what to specify and test, it&amp;#8217;s incomplete. I&amp;#8217;m not talking about helper classes which belong in one of those three boxes. I&amp;#8217;m not even talking about things like daemons, or mailers, or those kinds of components, because actually they still fit in the MVC model, just one without end-user interaction. What&amp;#8217;s missing from this diagram, I believe, is the dependencies.&lt;/p&gt;

&lt;p&gt;&lt;img src="/files/2007/10/mvc-diagram-2.png" /&gt;&lt;/p&gt;

&lt;p&gt;One of the problems which I (and many people, looking at the &lt;a href="http://rubyforge.org/pipermail/rspec-users/"&gt;rspec-users mailing list&lt;/a&gt; and the #rspec channel on freenode) have hit many times and which is very irritating is what to do about those validators and relationships. How do I specify my &lt;a href="http://www.inter-sections.net/2007/09/25/polymorphic-has_many-through-join-model/"&gt;polymorphic has_many :through&lt;/a&gt;, eh?&lt;/p&gt;

&lt;h3&gt;First, the big stuff&lt;/h3&gt;

&lt;p&gt;The first point I&amp;#8217;d like to make in this article is that with the Story engine, we now have the tools to specify almost the entire system. The mapping is fairly simple:&lt;/p&gt;

&lt;p&gt;&lt;img src="/files/2007/10/mvc-diagram-3.png" /&gt;&lt;/p&gt;

&lt;p&gt;First, you write Stories (in an outcome-focused way, with the &amp;#8220;Given/When/Then&amp;#8221; approach), which are essentially a much nicer way to express integration tests in a business-focused way.&lt;/p&gt;

&lt;p&gt;Next, you write specification to define how your code will make those stories pass. You write a behaviour-focused specification each for the model, the view, and the controller, because these are the key architectural separations. Please note that this doesn&amp;#8217;t imply you should write a specification for each method - specifications should be linked to behaviours, not low-level programming constructs. However, they are inevitably influenced by the architecture of the system.&lt;/p&gt;

&lt;p&gt;Finally, once the specifications pass, the stories should pass too. If later, you refactor or change your code, you have your integration tests holding you up and making sure your system is still working as a whole.&lt;/p&gt;

&lt;p&gt;You have two scenarios for a change: an internal change (e.g. refactoring) or an external change (change in the user requirements). The first is driven by a change in the code, the second is driven by a change in the Story.&lt;/p&gt;

&lt;p&gt;If you change your code, the following things sequence of events should happen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, the spec for the item you changed will break. Start by fixing that spec to be correct.&lt;/li&gt;
&lt;li&gt;Simultaneously, if you changed the behaviour, some of your Stories will break. This is not because they are wrong, though, only because your specs are mismatched - ie you&amp;#8217;ve updated your spec for your item, but not for its dependencies. Don&amp;#8217;t change your Stories at this point.&lt;/li&gt;
&lt;li&gt;You proceed to update the specs for everything which was dependent on the item you changed. They break. You update the code. They pass. You&amp;#8217;ll know that this process is complete because your Stories will pass again.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you change the Stories, the process is subtly different:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;If you change the Story, it will start by breaking.&lt;/li&gt;
&lt;li&gt;You then change some specs to make the Story pass.&lt;/li&gt;
&lt;li&gt;This may cause other Stories to break. At this point, you should not change those Stories (unless they are directly affected), but instead, fix the specs in the method outlined earlier, when looking at an internal change.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If your Stories are comprehensive enough, these processes will stop you from introducing bugs, while at the same time allowing you to spec the &amp;#8220;right way&amp;#8221; (at least according to me): by specifying behaviours rather than outcomes.&lt;/p&gt;

&lt;h3&gt;Issues with speccing validators and relationships&lt;/h3&gt;

&lt;p&gt;There are still some issues to do with validators and relationships. How should they be specced? The arguments tend to go like this:&lt;/p&gt;

&lt;p&gt;Someone writes code like:&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt;#################
&lt;/span&gt;describe &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;with neither facebook uid nor phone number set&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;  &lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;include&lt;/span&gt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;UserSpecHelper&lt;/span&gt;

  before&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;each&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should not be valid&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_not be_valid
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt;#################
&lt;/span&gt;describe &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;with facebook uid&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;  &lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;include&lt;/span&gt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;UserSpecHelper&lt;/span&gt;

  before&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;each&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;valid_facebook_attributes&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should be valid&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;save!
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should be_valid
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should reject duplicate facebook uid&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;save
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user_2&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;valid_facebook_attributes&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user_2&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_not be_valid
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This prompts someone else to ask:&lt;/p&gt;

&lt;p&gt;1 - What are you supposed to be testing?&lt;/p&gt;

&lt;p&gt;The answer to this is usually &amp;#8220;your own code&amp;#8221;. Therefore, a test (I refuse to call it a specification) like the above makes no sense. Yet is the most common way that people specify a validator.&lt;/p&gt;

&lt;p&gt;What am I testing here? The validator code. That&amp;#8217;s really pointless, because Rails already tests that. And it results in a lot of duplication (though technically, it can be argued to be &amp;#8220;not duplication&amp;#8221; because you&amp;#8217;re testing that the business rule of requiring a particular field is there, but I think that&amp;#8217;s just rationalising a bad practice). Ultimately, though, this is uncomfortable because you&amp;#8217;re testing an outcome, not specifying a behaviour. You may use rspec to do so, but it&amp;#8217;s still an outcome. And that&amp;#8217;s not what &lt;em&gt;behaviour&lt;/em&gt; driven design is about. Ultimately, this is testing, not specification.&lt;/p&gt;

&lt;p&gt;2 - But how do a specify one of those weird validator things?&lt;/p&gt;

&lt;p&gt;I think a lot of the issue is also caused by the simple language constraint that specifying validators and relationships is just plain fugly at the moment. Here&amp;#8217;s the code provided by David Chelimsky (chief maintainer of rspec):&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should validate_presence_of digits&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;  &lt;span class="support support_class support_class_ruby"&gt;PhoneNumber&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;expects&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;validates_presence_of&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;with&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;digits&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  load &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;RAILS_ROOT&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;/app/models/phone_number.rb&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Now I love rspec, and very much respect David - I&amp;#8217;ve had a few chats with him on freenode#rspec and he&amp;#8217;s a very smart guy - but this code is just nasty! That nastiness is required to get around the fact that the validator is loaded when the class loads, so can&amp;#8217;t be specified as something that will happen later.&lt;/p&gt;

&lt;p&gt;As per the Sapir-Whorf hypothesis that BDDers know and love, language drives behaviour, and nasty language like this doesn&amp;#8217;t encourage people to go this way, even though, as I&amp;#8217;ll explain a bit further down, I think this is actually the correct way to go, in spirit if not in form.&lt;/p&gt;

&lt;p&gt;3 - But if I just specify that &amp;#8220;thing&amp;#8221;, how do I know that it actually does what it&amp;#8217;s supposed to?&lt;/p&gt;

&lt;p&gt;A couple of weeks ago I would have replied: &lt;em&gt;This is not a valid concern. It just shows that you really need to write that spec. You need to find out how your code is going to work &lt;/em&gt;before&lt;em&gt; you write it. Surely that should be obvious?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But then, like all things, this is not quite so black and white. There are validation and relationship constructs which are complex enough that you want to not only specify them, you also want to unit test that they work, and that they continue working even when things change, for instance when you deploy Rails 2.0. And that&amp;#8217;s the key to solving this puzzle. The &amp;#8220;specification&amp;#8221; in point 1 looks wrong because it&amp;#8217;s not a specification, it&amp;#8217;s a unit test. It&amp;#8217;s not an integration test, so it doesn&amp;#8217;t fit in the Story Writer. But it&amp;#8217;s also not a specification, so it doesn&amp;#8217;t fit in your User spec.&lt;/p&gt;

&lt;h3&gt;So, the solution?&lt;/h3&gt;

&lt;p&gt;I put forward that this item belongs in a third category, that we thought eliminated by the arrival of BDD, but which actually should still exist: unit tests. Specifically, unit tests relating to the behaviour of third party code, or of your interpretation of that code. So these are not system integration tests, in the sense that they are not testing your system as a whole. They are more like unit integration tests, there to codify your understanding of the way the rest of the world behaves.&lt;/p&gt;

&lt;p&gt;As such, they do not fit in the Story Runner. They have nothing to do with user requirements. What we need is a new directory in the rspec folder, dedicated to what I would like to call Assumption Tests. They are tests of your assumptions about your dependencies. As such, they are both redundant and essential. They are redundant in an ideal world where you know exactly how the external code you use works and you know about any changes to it. They are essential in the ugly world where you have to be just that little bit paranoid about other people&amp;#8217;s code, even if it&amp;#8217;s specified and tested up the wazoo, because sometimes things change in a way that breaks your assumptions.&lt;/p&gt;

&lt;p&gt;And, importantly, these are not specifications. They are unashamedly outcome-driven. This is especially acceptable when you consider that they are not specifying your own code, but testing other people&amp;#8217;s code to make sure it fits your assumptions.&lt;/p&gt;

&lt;p&gt;Without further ado, here&amp;#8217;s an example of one such assumption test:&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_model"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;ActiveRecordTester&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;  &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; This makes this model tableless
&lt;/span&gt;  &lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;self.columns&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;()&lt;/span&gt;&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;columns&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;||=&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_statement punctuation_separator_statement_ruby"&gt;;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
  &lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;self.column&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;name&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; sql_type &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; default &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; null &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;
    columns &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ActiveRecord&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;ConnectionAdapters&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Column&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;name&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; default&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; sql_type&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;to_s&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; null&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  column &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;foo&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;string&lt;/span&gt;

  &lt;span class="support support_function support_function_activerecord support_function_activerecord_rails"&gt;validates_presence_of&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;foo&lt;/span&gt;
&lt;/span&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt;#################
&lt;/span&gt;describe &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Presence Validator&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;
  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should not be valid without foo&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;test&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ActiveRecordTester&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;test&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_not be_valid
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should be valid with foo&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;test&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;ActiveRecordTester&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;foo&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;1&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;test&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should be_valid
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Once you&amp;#8217;ve got this in place, you should never need to test the outcome of validates&lt;em&gt;presence&lt;/em&gt;of again. So the code in example 1 is now obsolete, and your specifications can remain entirely behaviour-driven, rather than including bits and pieces of outcome testing. All you need to specify is that, say, your User model calls &amp;#8220;validates&lt;em&gt;presence&lt;/em&gt;of&amp;#8221; for facebook_uid in the way that&amp;#8217;s codified and auto-tested in your assumptions.&lt;/p&gt;

&lt;p&gt;So now you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;specs for controllers&lt;/li&gt;
&lt;li&gt;specs for models&lt;/li&gt;
&lt;li&gt;specs for views&lt;/li&gt;
&lt;li&gt;stories for the whole system&lt;/li&gt;
&lt;li&gt;assumption tests for things which you didn&amp;#8217;t write but want to test anyway&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sorry for the long article, but there were a fair number of ideas to cover. I&amp;#8217;d love to hear comments about this, as it&amp;#8217;s all still a bit fresh to me. You can put those comments below, or even comment on your own blog (I have trackback enabled). Thanks for reading!&lt;/p&gt;</description>
      <pubDate>Fri, 19 Oct 2007 12:33:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:408d5bc1-1c88-4cea-b369-b3bdb471034f</guid>
      <comments>http://inter-sections.net/2007/10/19/what-to-test-and-specify-and-where-to-do-it#comments</comments>
      <category>Technology</category>
      <category>Ruby / Rails</category>
      <category>RSpec</category>
      <trackback:ping>http://inter-sections.net/trackbacks?article_id=what-to-test-and-specify-and-where-to-do-it&amp;day=19&amp;month=10&amp;year=2007</trackback:ping>
      <link>http://inter-sections.net/2007/10/19/what-to-test-and-specify-and-where-to-do-it</link>
    </item>
    <item>
      <title>Specifying a before_filter and/or private method</title>
      <description>&lt;p&gt;How do you write specs for a private or protected method? Specifically (as this is often the case), how do you write a spec for a before_filter?&lt;/p&gt;

&lt;p&gt;The answers that I found while looking online were not very explicit. The main points seemed to be &amp;#8220;don&amp;#8217;t test private/protected method&amp;#8221;, &amp;#8220;you should be specifying expected behaviours in the places where they&amp;#8217;re used.&amp;#8221; I decided to write this article to clarify how I&amp;#8217;ve interpreted that advice.&lt;/p&gt;

&lt;p&gt;Essentially, I decided to follow the advice given online. Don&amp;#8217;t test the methods, test the behaviours you expect. Let&amp;#8217;s take a simple example and see what this means in practice.&lt;/p&gt;

&lt;p&gt;For our facebook application, I have a facebook controller which handles all the facebook posts (very RESTless, but that&amp;#8217;s facebook for you!). There are two things that I want to see happen with every authenticated facebook action, and I&amp;#8217;ve defined a filter for each of them:&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_controller"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;FacebookController&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ApplicationController&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="support support_function support_function_actionpack support_function_actionpack_rails"&gt;before_filter&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;require_facebook_install&lt;/span&gt;
  &lt;span class="support support_function support_function_actionpack support_function_actionpack_rails"&gt;before_filter&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;set_user&lt;/span&gt;

  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;index&lt;/span&gt;&lt;/span&gt;
&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; ...
&lt;/span&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;other_action&lt;/span&gt;&lt;/span&gt;
&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; ...
&lt;/span&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;private&lt;/span&gt;
  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;set_user&lt;/span&gt;&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;find_by_facebook_uid&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;fbparams&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;user&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;include&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;interactions&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; fbparams&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;friends&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;
        &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;cached_friend_uids &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; fbparams&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;friends&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;
        &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;save
      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;if&lt;/span&gt; fbparams&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;session_key&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;
        &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;facebook_session_key &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; fbparams&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;session_key&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;
        &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;save
      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;/span&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Now, require&lt;em&gt;facebook&lt;/em&gt;install is given by &lt;a href="http://rfacebook.rubyforge.org/"&gt;RFacebook&lt;/a&gt;, so all I want to specify is that for certain actions, this filter must be called. All that it does is return true if proper parameters are included, that represent a valid facebook session. There&amp;#8217;s a lot of those parameters, and I only use a few of them. The only time when I might want to have this filter return false is if I was testing what would happen with a blank session. However, this should never happen in my specifications, since I&amp;#8217;m not trying to spec RFacebook, but my own code. This is the simple, shared spec that I wrote:&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;describe &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Facebook Action&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;shared&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;  &lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;include&lt;/span&gt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;FacebookControllerSpecHelper&lt;/span&gt;

  before&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;each&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;controller&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;require_facebook_install&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;and_return&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;#8217;s not much to look at, and it doesn&amp;#8217;t need to be! How to use it? Just include this (which I&amp;#8217;d like to call a partial spec, but the rspec keyword is &amp;#8220;shared&amp;#8221;) into other specs:&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;describe &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;FacebookController&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;index page&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;  &lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;include&lt;/span&gt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;FacebookControllerSpecHelper&lt;/span&gt;

  it_should_behave_like &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Facebook Action&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;

  before&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;each&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;create&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;facebook_uid&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;do_post&lt;/span&gt;&lt;/span&gt;
    post &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;index&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should render the canvas&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    do_post
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;I can do this for any of the other facebook &amp;#8220;pages&amp;#8221;, of course. So far so good. Adding this &amp;#8220;it&lt;em&gt;should&lt;/em&gt;behave&lt;em&gt;like&amp;#8221; directive ensures that the filter &lt;em&gt;is&lt;/em&gt; called for the actions where I specify that it needs to be called. Handily enough, this also removes the need for me to mock require&lt;/em&gt;facebook_install in every one of those specs, since it&amp;#8217;s mocked just once in the shared spec.&lt;/p&gt;

&lt;p&gt;How about set&lt;em&gt;user? That&amp;#8217;s a little bit more tricky. In this case, I have actually written set&lt;/em&gt;user myself, so I need to specify it. But I can&amp;#8217;t! It&amp;#8217;s a private method, therefore invisible to my specs! Oh dear. Let&amp;#8217;s go back to the initial advice. &lt;em&gt;Don&amp;#8217;t specify methods, specify behaviours where they&amp;#8217;re used.&lt;/em&gt; Okay. Thinking about it on a basic level, this makes sense. I do want to specify that my filter is working for each of the actions I&amp;#8217;ve told it to work for. One way to do this would be to specify that set_user must function properly in each of those actions. The smart way is of course to put that into a partial spec as well.&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;describe &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Facebook Action With User&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;shared&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;  &lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;include&lt;/span&gt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;FacebookControllerSpecHelper&lt;/span&gt;

  before&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;each&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;create&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;facebook_uid&lt;/span&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_key-value"&gt;=&amp;gt;&lt;/span&gt; valid_fbparams&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;user&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;

    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;controller&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;fbparams&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;at_least&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;once&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;and_return&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;valid_fbparams&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    &lt;span class="support support_class support_class_ruby"&gt;User&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;find_by_facebook_uid&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;at_least&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;once&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;and_return&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should call set_user&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    do_post
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should save the user's cached friends&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;cached_friend_uids=&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;with&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;valid_fbparams&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;friends&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;save&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;at_least&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;once&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;

    do_post
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should save the user's session key&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;facebook_session_key=&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;with&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;valid_fbparams&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;session_key&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;save&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;at_least&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;once&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;

    do_post
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Those are the three things I expect my set&lt;em&gt;user before&lt;/em&gt;filter to do for me. So now I can include them in my controller action spec as well!&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;describe &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;FacebookController&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;index page&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;  &lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;include&lt;/span&gt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;FacebookControllerSpecHelper&lt;/span&gt;

  it_should_behave_like &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Facebook Action&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
  it_should_behave_like &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Facebook Action With User&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;

  &lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;do_post&lt;/span&gt;&lt;/span&gt;
    post &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;index&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should render the canvas&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;controller&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;instance_variable_set&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;@user&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;user&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    do_post
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;And that&amp;#8217;s all. The best part is, including the &amp;#8220;Facebook Action With User&amp;#8221; behaviour automatically mocks that part of the process for me in all the actions where I put it, so that I don&amp;#8217;t need to do it again and again. By extracting those apparently intractable filters into their own shared spec, I&amp;#8217;ve not only managed to spec them, but I&amp;#8217;ve also reduced the clutter in my mocking code. I now only mock the things which are relevant to the current action, instead of having to mock everything to &amp;#8220;make things work&amp;#8221;.&lt;/p&gt;

&lt;p&gt;On the downside, by DRYing up this code it&amp;#8217;s become a tad harder to follow at a glance, but I think it&amp;#8217;s more readable once you&amp;#8217;ve figured out what the included shared specs provide.&lt;/p&gt;

&lt;p&gt;One final caveat: if you mock something in your shared specs, don&amp;#8217;t mock it again in your concrete specs. Otherwise, you will get errors about your shared spec being broken.&lt;/p&gt;

&lt;p&gt;I hope you found this article useful. Please feel free to leave a comment below if you agree or disagree with this method - particularly if you have something better to suggest!&lt;/p&gt;</description>
      <pubDate>Thu, 04 Oct 2007 13:12:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:2724ebf7-59cd-43c3-97a4-f1629de0405f</guid>
      <comments>http://inter-sections.net/2007/10/04/specifying-a-before_filter-and-or-private-method#comments</comments>
      <category>Technology</category>
      <category>Ruby / Rails</category>
      <category>RSpec</category>
      <category>Facebook</category>
      <trackback:ping>http://inter-sections.net/trackbacks?article_id=specifying-a-before_filter-and-or-private-method&amp;day=04&amp;month=10&amp;year=2007</trackback:ping>
      <link>http://inter-sections.net/2007/10/04/specifying-a-before_filter-and-or-private-method</link>
    </item>
    <item>
      <title>The difference between TDD and BDD</title>
      <description>&lt;p&gt;&#8220;It&#8217;s all about the words&#8221;. &#8220;Focus on behaviour&#8221;. &#8220;Design your API as a client of your own API&#8221;. &#8220;It&#8217;s a clearer way to express the same thing, so it helps communication with stakeholders&#8221;. Those are all typical responses to the questions &#8220;Why is &lt;a href="http://behaviour-driven.org/"&gt;Behaviour Driven Development&lt;/a&gt; better than &lt;a href="http://www.agiledata.org/essays/tdd.html"&gt;Test Driven Development&lt;/a&gt;? Why should I switch to BDD?&#8221;&lt;/p&gt;

&lt;p&gt;I&#8217;ve given this some thought. All these reasons are correct, of course. BDD uses different wording, which is much clearer. BDD focuses on specifying behaviour (though the benefit of that is often not clarified, and some people will claim that all you&#8217;re doing is writing your code twice). Designing your own API as your own client means you will design it more easily and more quickly. Being clearer, BDD does help to communicate with other coders or stakeholders (although I&#8217;m not entirely sure that the average spec is really client-friendly enough to show unfiltered).&lt;/p&gt;

&lt;p&gt;Some of those are not really benefits of BDD, however - rather, they are benefits of Designing. Many programmers (particularly in the less sophisticated parts of the agile movement) tend to focus on code and ignore the rest. BDD provides them with a neat, coder-friendly way of doing design and specification. Of course that helps! There&amp;#8217;s a reason why the industry standard development processes include a &lt;em&gt;design&lt;/em&gt; phase, after all - it&amp;#8217;s not just to delay the project!&lt;/p&gt;

&lt;p&gt;I think there&#8217;s another important reason why BDD is better, &lt;em&gt;as a test suite&lt;/em&gt;. It helps make your test suite less brittle &lt;em&gt;in the face of specification changes&lt;/em&gt;. Here&#8217;s the reasoning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;em&gt;Please have a look at &lt;a href="http://evang.eli.st/blog/2008/2/3/it-s-not-about-state-or-interactions-it-s-about-behavior"&gt;this article&lt;/a&gt; from Pat Maddox. BDD is a fairly new field that&amp;#8217;s still evolving, and Pat&amp;#8217;s article is right on the money. The approach I outline in this article is what Pat would call &amp;#8220;pure interaction testing&amp;#8221; and, as he points out, it should not be a goal - only an available technique. Currently, I use pure interaction testing for Rails controller testing, and state-based testing for ActiveRecord models. There&amp;#8217;s certainly a place for the ideas exposed in this article, but they shouldn&amp;#8217;t be used blindly everywhere.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;BDD focuses on specifying what will happen next. The basic sentence structure of a BDD spec is:&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="text text_plain"&gt;&lt;span class="meta meta_paragraph meta_paragraph_text"&gt;This should happen; then this should happen; then this. Tell me if that doesn&#8217;t happen when I say &#8220;foo&#8221;. Foo.
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;TDD, on the other hand, focuses on setting up a set of conditions and then looking at the output:&lt;/p&gt;

&lt;pre class="textmate-source cobalt"&gt;&lt;span class="text text_plain"&gt;&lt;span class="meta meta_paragraph meta_paragraph_text"&gt;Foo. Is Bar set to the right value? What about Baz?
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Put in other words, BDD specifies behaviours while TDD specifies outcomes. The difference is more than just language, though. It&#8217;s a paradigm shift that has some severe consequences.&lt;/p&gt;

&lt;p&gt;The main one, in my view, is that behaviours can be layered, while outcomes cannot. This might sound a bit cryptic, so let me explain. Let&#8217;s use the analogy of a big machine. At one end, you put a variety of raw materials, and at the other, you get a widget. Outcome testing will examine the widget from all angles. It will ask &#8220;Does this widget perform the functions that I expect a widget to perform?&#8221;. This is basically black box testing - and that&#8217;s what most integration tests do (and, sadly, many unit tests, as it&#8217;s often hard to separate the two without extensive mocking, which requires deep knowledge of the internals of the module you&#8217;re testing).&lt;/p&gt;

&lt;p&gt;Behaviour specification turns this upside down. Instead of trying to specify the outcome, and using mocking only where you absolutely need to in order to get the thing working, you start with the goal to specify precisely those internals that you tried to avoid in TDD. &#8220;The machine should be able to turn sand and gold flakes into gold flaked glass; to do this, it should heat up the sand into molten glass. Then it should insert the gold flakes.&#8221; This requires internal knowledge of the machine.&lt;/p&gt;

&lt;p&gt;Hopefully this is clear so far. Now here&#8217;s the clincher, the real advantage of behaviour specification over outcome testing. In order to test an outcome, you need all the parts up to that outcome to have done their job. If I want to test that my widget has a gold-flaked glass pane in it, I need the rest of the widget-building to have succeeded and not produced a molten lump of goo. In other words, outcome testing is quite brittle. If one of the parts malfunctions, there will be many knock-on effects onto other tests. You might point out that this is why we have unit tests, but my point is, BDD enables you to design your unit tests properly. Let&#8217;s take a fairly simple method as an example.&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;Mogrifier&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; Polator&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;transmogrify&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;foo&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; bar&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;
    foo&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;extrapolate!
    bar&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;extrapolate!

    baz &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; intrapolate&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;foo&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; bar&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;

    &lt;span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby"&gt;return&lt;/span&gt; ultrapolate&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;baz&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;With a Test-First approach, we might have written something like this as a test, before writing this code:&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;test_mogrifier&lt;/span&gt;&lt;/span&gt;
  foo &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; test_foo
  bar &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; test_bar

  test_result &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Mogrifier&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;transmogrify&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;foo&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; bar&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;

  assert test_result&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;ultrapolated?
  assert test_result&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;intrapolated?
  assert test_result&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;contains&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;foo&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;relevant_bit&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  assert test_result&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;contains&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;bar&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;relevant_bit&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;How would you write this as a specification?&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;describe &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Mogrifier&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;transmogrify&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;
  before&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;each&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;mogrifier&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Mogrifier&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should extrapolate foo&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    foo &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;foo&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
    foo&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;extrapolate!&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;and_return&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;extrapolated foo&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;

    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;mogrifier&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;my_method&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;foo&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;bar&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should extrapolate bar&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    bar &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;bar&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;
    bar&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;extrapolate!&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;and_return&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;extrapolated bar&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;

    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;mogrifier&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;my_method&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;foo&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; bar&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should intrapolate&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;mogrifier&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;intrapolate&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;mogrifier&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;my_method&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;foo&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;bar&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should ultrapolate&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;mogrifier&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;ultrapolate&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;

&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Why is the test more brittle? It&amp;#8217;s brittle because if the specification changes and states that actuallly, the transmogrifier should also encrypt its results, your test will break, whereas &lt;strong&gt;not one&lt;/strong&gt; of your specs will break. In a BDD world, you&amp;#8217;d write:&lt;/p&gt;

&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;  it &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;should encrypt&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do
&lt;/span&gt;    mock_baz &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; mock&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;baz&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    mock_baz&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;encrypt&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;mogrifier&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;should_receive&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;ultrapolate&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;and_return&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;mock_baz&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;
  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;And then you&amp;#8217;d add the encrypt call to the transmogrify method. With TDD, on the other hand, any of your tests that depend on the outcome of the transmogrifier will have to change. You might even be quite stuck at this point, in this specific example, if the encryption happens to be one-way - if that were the case, you won&amp;#8217;t be able to test the outcome at all, since it will be opaque! Then you&amp;#8217;d have to redesign your code so that transmogrify doesn&amp;#8217;t actually encrypt stuff, but some other method does. What a pain!&lt;/p&gt;

&lt;p&gt;Behaviour specifications enable you to ensure that your transmogrifier code keeps extrapolating and intrapolating as required - no matter what it does with its input later. If it needs to do other stuff too, that&amp;#8217;s fine, you can specify it as well - but each specification will (or should) focus on a single behaviour and that way, as long as your spec passes, you know that the specification is being met, and that foo and bar are still being extrapolated (in this example).&lt;/p&gt;

&lt;p&gt;As the behaviours multiply, and the layering increases, this becomes even more useful. Because of the focus of each specification, there is rarely any need to change more than a handful of specifications when the code changes (if the specs are well-written and cleanly split out into small and specific behaviours). For instance, if the Polator changes its processes (but retains its interface), the Transmogrifier test code will remain the same. BDD encourages low coupling of tests, which, to be fair, TDD doesn&amp;#8217;t encourage. In TDD, it&amp;#8217;s easier to write a test that uses real objects (at least at first). In BDD, you simply cannot specify behaviours without using mocks.&lt;/p&gt;

&lt;p&gt;This is the major winning point of BDD for me, the reason why it feels so much more &lt;em&gt;right&lt;/em&gt;. I think that the clarity, the speed, design, words, etc, are all nice bonuses to this main benefit. If you have any comments on this, any disagreements, etc, do feel free to post something below!&lt;/p&gt;

&lt;h4&gt;PS:&lt;/h4&gt;

&lt;p&gt;On the other hand, please note that I don&amp;#8217;t suggest that we shouldn&amp;#8217;t use tests at all. As mentioned &lt;a href="http://pezra.barelyenough.org/blog/2007/06/mocking/"&gt;here&lt;/a&gt;, specs do not validate whether your system actually hangs together and works on the whole. Tests are the ones to give you that.&lt;/p&gt;</description>
      <pubDate>Wed, 03 Oct 2007 08:59:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:29d92bf7-c7a8-4311-a91b-34832903debd</guid>
      <comments>http://inter-sections.net/2007/10/03/the-difference-between-tdd-and-bdd#comments</comments>
      <category>Technology</category>
      <category>Ruby / Rails</category>
      <category>RSpec</category>
      <trackback:ping>http://inter-sections.net/trackbacks?article_id=the-difference-between-tdd-and-bdd&amp;day=03&amp;month=10&amp;year=2007</trackback:ping>
      <link>http://inter-sections.net/2007/10/03/the-difference-between-tdd-and-bdd</link>
    </item>
  </channel>
</rss>
