[rspec-users] defining context(s) dynamically

David Chelimsky dchelimsky at gmail.com
Thu Feb 15 13:54:50 EST 2007

On 2/15/07, Jerry West <jerry.west at ntlworld.com> wrote:
>  Q. Why does code which defines a context work in the controller_spec file
> and not in a 'require'd helper file?
>  A. Because spec uses the filename to tell it what type of context
> (:controller, :model) it is creating.
>  Fix: use the (undocumented?) second parameter to #context(), :context_type
> => :controller.
>  Quite how this works, I do not know; the rdocs don't mention it and
> according to the source context doesn't take a second argument (except a
> block).  My Ruby-fu isn't up to explaining it; if anyone else would like to
> do so that would be nice.
>  Hope this helps someone else save a half hour or so.
>  Rgds,
>    Jerry
>  Further details:
>  If I define a method which dynamically constructs a context in my
> controller_spec.rb file it works fine:
>  def restful_edit_specs(resource)
>    context "GET /#{resource}/:id;edit (:edit)" do
>      controller_name resource
>      resource = resource.to_s
>      sym = resource.singularize
>      klass = resource.classify
>      setup do
>        @mock = mock_model sym # based on
> http://metaclass.org/2006/12/22/making-a-mockery-of-activerecord
>        @model = Object.const_get(klass)
>        @model.should_receive(:find).with(@mock.id).and_return(@mock)
>      end
>      def do_get() get :edit, :id => @mock.id end
>      specify "should be successful" do
>        do_get
>        response.should_be_success
>      end
>      specify "should render edit.rhtml" do
>        do_get
>        controller.should_render :edit
>      end
>      specify "should find the #{klass} requested" do
>        @model.should_receive(:find).and_return(@mock)
>        do_get
>      end
>      specify "should assign the found #{klass} for the view" do
>        do_get
>        assigns(sym).should_equal @mock
>      end
>    end
>  end
>  restful_edit_specs(:assessments)
>  This all works fine when defined in the xx_controller_spec.rb file.
>  But if I move the exact same code to a helper file and require it, spec
> gets confused:
>  .../rspec-
> `call': undefined method `controller_name' for
> #<Spec::Runner::ContextEvalModule:0xb70496a8>
> (NoMethodError)
>   ... etc etc...
>  Clearly, there's some magic involved which means the context does not know
> what it's about (it was at this point in typing my original plea for help
> that I remembered seeing the :context_type parameter in the specs for the
> rspec_on_rails plugin itself).
>  Changing the context line to
>      context "GET /#{resource}/:id;edit (:edit)", :context_type =>
> :controller do
>  allows the specs to function as ex-spec-ted.

This is one of those "convention over configuration" things.
Spec::Rails goes out of its way to provide different contexts for
different types of specs, each providing specific facilities that are
relevant to that kind of spec (model/view/controller/helper). Put your
specs in the right directories and you get the right kind of context.

The undocumented-second-parameter was added, as you note, to support
our own specs of the plugin. The likelihood is that it will remain,
but it is undocumented and subject to change without notice, so you do
absorb some risk in using it.

What is the value you are looking for by bypassing the convention
here? I'm asking because perhaps there is a missing feature we can
tease out of this.


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

More information about the rspec-users mailing list