[rspec-users] Specs for ApplicationController, where to put them?
Wincent Colaiuta
win at wincent.com
Wed May 30 14:36:50 EDT 2007
El 30/5/2007, a las 1:52, David Chelimsky escribió:
> I don't view that as a workaround at all. You should always be able to
> run any example file by itself. If such a file relies on other files,
> then it should require them.
>
> Another thing you could do is to put shared behaviours in spec/shared/
> and require everything in spec/shared from spec/spec_helper.
>
> The fact that the shared examples are in another file should have no
> bearing on whether they have runtime access to whatever is in the
> behaviours that include them. This all sounds odd to me. Can you post
> a backtrace please?
I've been looking at the code for this and was a bit puzzled by the
following in lib/spec/dsl/behaviour.rb
def add_shared_behaviour(behaviour)
return if behaviour.equal?(found_behaviour =
find_shared_behaviour(behaviour.description))
...
The intent is evidently to skip over previously instantiated shared
behaviours, but I can't think of too many real-world cases where the
object identity test (equal?) will succeed. About the only place it
will succeed is in the spec (spec/spec/dsl/shared_behaviour_spec.rb):
it "should NOT complain when adding a the same shared
behaviour again (i.e. file gets reloaded)" do
behaviour = behaviour_class.new("shared behaviour") {}
behaviour_class.add_shared_behaviour(behaviour)
behaviour_class.add_shared_behaviour(behaviour)
end
Here the exact same instance is being added and it is naturally
skipped. But try adding something like the following to your
spec_helper.rb file and watch the exceptions being raised when you do
a "rake spec":
describe "foobar", :shared => true do
end
Here every spec which includes the spec_helper.rb file will trigger
an ArgumentError because the same shared behaviour gets re-evaluated
over and over again and "found_behaviour" is set each time:
def add_shared_behaviour(behaviour)
return if behaviour.equal?(found_behaviour =
find_shared_behaviour(behaviour.description))
raise ArgumentError.new("Shared Behaviour '#
{behaviour.description}' already exists") if found_behaviour
I think the solution here is to relax the equality comparison, use
"==" instead of "equal?":
Index: rspec/lib/spec/dsl/behaviour.rb
===================================================================
--- rspec/lib/spec/dsl/behaviour.rb (revision 2060)
+++ rspec/lib/spec/dsl/behaviour.rb (working copy)
@@ -6,7 +6,7 @@
class << self
def add_shared_behaviour(behaviour)
- return if behaviour.equal?(found_behaviour =
find_shared_behaviour(behaviour.description))
+ return if behaviour == (found_behaviour =
find_shared_behaviour(behaviour.description))
raise ArgumentError.new("Shared Behaviour '#
{behaviour.description}' already exists") if found_behaviour
shared_behaviours << behaviour
end
I've made this change against the RSpec trunk and "rake pre_commit"
passes all specs. But I actually think that there might be some
mistakes in the specs themselves:
it "should NOT complain when adding a the same shared
behaviour again (i.e. file gets reloaded)" do
behaviour = behaviour_class.new("shared behaviour") {}
behaviour_class.add_shared_behaviour(behaviour)
behaviour_class.add_shared_behaviour(behaviour)
end
The two problems I see here are:
- behaviour isn't actually a shared behaviour; you'd need to use
"make_shared_behaviour" for that
- adding the exact same instance as in the spec is not the same as
what happens when the file gets reloaded, because when you reload a
file, the "describe" block is actually going to instantiate a new
(different) Behaviour instance very time
I could change this spec to make it correct but then the following
spec will no longer pass:
it "should complain when adding a second shared behaviour with
the same description" do
make_shared_behaviour("shared behaviour") {}
lambda { make_shared_behaviour("shared behaviour")
{} }.should raise_error(ArgumentError)
end
It seems to me that to get the correct behaviour this spec will have
to be jettisoned... It's not possible to have shared behaviours in
reloaded files without relaxing the requirement above...
Thoughts?
Cheers,
Wincent
More information about the rspec-users
mailing list