[rspec-users] Specs for ApplicationController, where to put them?

David Chelimsky dchelimsky at gmail.com
Wed May 30 17:11:34 EDT 2007


On 5/30/07, Wincent Colaiuta <win at wincent.com> wrote:
> 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?

I think you're spot on about all of this. I'm thinking that a simple
solution would be that each time a shared behaviour is registered, the
location of its definition can be registered as well. Then we can
ignore the ones defined in the same place when a file gets reloaded,
but still complain when another one is defined with the same name from
a different location.

WDYT?

>
> Cheers,
> Wincent
>
>
> _______________________________________________
> rspec-users mailing list
> rspec-users at rubyforge.org
> http://rubyforge.org/mailman/listinfo/rspec-users
>


More information about the rspec-users mailing list