[rspec-users] Formatting shared example descriptions with test data

Wincent Colaiuta
Mon, 26 Jul 2010 14:44:26 -0000

El 26/07/2010, a las 14:09, Ashley Moran escribi?:

> The solution I''m playing with is to extract shared contract (ie
shared example groups) that you can mix into a spec for a host class (eg User,
Checklist) above to prove the feature (here collections) works, without
reference to the implementation.  (The specs inside DomainLib prove the general
case.)
>
> With the help of this spec_helper incantation:
>
>  module SpecHelperObjectExtensions
>    def contract(name, &block)
>      shared_examples_for(name, &block)
>    end
>  end
>  include SpecHelperObjectExtensions

Personally I wouldn''t do this. It makes it harder for anybody coming to
your project to understand what''s going on, because they see this
"contract ''foo'' do" construct and don''t
know what it is unless they dig into your spec_helper. If you really want the
word contract to appear in there I would just write the shared examples like
this:

  shared_examples_for ''representation contract'' do
    ...
  end

>  RSpec.configure do |c|
>    c.alias_it_should_behave_like_to(:it_satisfies_contract,
''satisfies contract:'')
>  end

And if you go with names like "representation contract" then you might
want your alias to be just "it_satisifies" instead...

>      it "is false if any property is different" do
>        properties.each do |property|
>          representation_class.new(default_attributes).should_not eq(
>
representation_class.new(default_attributes_with_different_value_for(property))
>          )
>        end
>      end

So if I''m reading you correctly, this is where the "aspect of
behavior that can occur N times" comes in, right? AFAIK the typical way to
do this is via "macros" (ie. generating examples on the fly, typically
keeping to examples of one assertion per iteration of the loop). So
it''s just a minor tweak of what you''ve got there:

  properties.each do |property|
    it "is false if #{property} is different" do
      ...
    end
  end

But alas, this pattern won''t work with shared example groups. I
don''t know of any way to pass the "properties" variable in
this case, and even if you could it wouldn''t work anyway because,
AFAIK, the shared example group is itself only evaluated once when the file is
first read. It isn''t re-evaluted each time it is included in another
example group. At least, that''s my understanding of it. I might be
wrong about that. So, looks like you''re stuck with having multiple
assertions inside a single "it" block.

> This is fine for a class, but the behaviour I want to prove with a
Collection needs to be mixed in once per collection, eg (the last two are made
up):
>
>  describe User do
>    it_satisfies_contract "Entity Collection", for:
"checklist_templates"
>    it_satisfies_contract "Entity Collection", for:
"groups"
>    it_satisfies_contract "Entity Collection", for:
"delegated_actions"
>  end

Here the "standard" way of parametrizing this would be via blocks
("standard" in inverted commas because the ability to pass a block
here is such a recent addition to RSpec).

Cheers,
Wincent