On Jul 26, 2010, at 8:55 am, Wincent C. wrote:
Seems to me that including the same shared example group twice in the same “describe” block is a bit of an abuse, to be honest. I don’t think it was ever really intended to be used in that way.
You’re right, it clearly wasn’t intended for this. I’m trying to find
the best way to express the behaviour I want without bending the current
syntax of RSpec too much. This is indeed a toy example, so let me
explain the real situation in more detail.
I’m doing a small side project to make a checklist app. As part of
that, I’m trying to extract out a library similar to Naked Objects[1].
One of the things that can be factored out is collections inside
entities. So I currently have, as examples:
class User
extend DomainLib::Entity::ClassExtensions
include DomainLib::Entity::InstanceExtensions
collection :checklist_templates, of: :checklist_template,
class_name: “ChecklistTemplate”
end
and
class ChecklistTemplate
extend DomainLib::Entity::ClassExtensions
include DomainLib::Entity::InstanceExtensions
collection :items, of: :item, class_name: "ChecklistTemplateItem"
end
Now one of the thing that bugs me about using ORM (eg ActiveRecord,
DataMapper) features for this is you’re then faced with the dilemma of
do you do an integration test of the collection functionality, which
duplicates a lot of the testing effort put into the ORM, or do you mock
this out, and risk having false positives because the ORM behaves
differently than your test setup assumes?
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
RSpec.configure do |c|
c.alias_it_should_behave_like_to(:it_satisfies_contract, ‘satisfies
contract:’)
end
I’ve already been able to extracted contract, which is for
Representation (basically, a view object that isn’t much more than a
Struct):
Params:
* representation_class
* properties
contract “Representation” do
# …
# Setup and other examples omitted
# …
describe "#==" do
it "is true for Representations with the equal attributes" do
representation_class.new(default_attributes).should eq
representation_class.new(default_attributes)
end
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
end
end
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
I know you probably have some real example in mind hiding behind that toy example, but I believe anything you want to test can be written in the same way (ie. without needing to inject the “” into your shared examples).
So as you can see, in the real (non-toy) example there’s no object to be
described: it’s an aspect of behaviour of the test subject, and one than
can occur N times. I’m aware that I’m twisting RSpec quite a bit to try
to achieve this.
If you (or anyone) have any thoughts though, I’d love to hear them.
This one is messing with my head a bit
Cheers
Ash
[1] http://www.nakedobjects.org/
–
http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashleymoran