Stephen Bannasch
2010-May-11 01:48 UTC
[rspec-users] questions about meta-programming in a shared_examples group
I''ve created a shared_examples group that helps me dry up the testing of a large set of similar rails controllers. These controllers have an html interface but mostly what I am testing with the shared_examples group is the rendering of four different forms of xml that relate to running a dynamically created Java Web Start jnlp. The html reports when running one of the controller specs looks like this: Embeddable::DataCollectorsController GET show with mime type of otml renders the requested data_collector as otml without error Here''s an example of what one of the controller specs looks like: http://github.com/stepheneb/rigse/blob/master/spec/controllers/embeddable/data_collectors_controller_spec.rb require ''spec_helper'' describe Embeddable::DataCollectorsController do it_should_behave_like ''an embeddable controller'' def with_tags_like_an_otml_data_collector with_tag(''OTDataCollector'') do with_tag(''source'') do with_tag(''OTDataGraphable'') do with_tag(''dataProducer'') end end with_tag(''xDataAxis'') do with_tag(''OTDataAxis'') end with_tag(''yDataAxis'') do with_tag(''OTDataAxis'') end end end end I love how clearly each controller spec reads now and how the part that is different in the otml rendering stands out. But I wondered if the way I am using lambdas in the shared_examples helper is fragile and might break if internals in rspec change. The meta-programming I did to get some of this to work seemed a bit messy and I was wondering if there was a simpler way. The describe statement in the shared_examples_for ''an embeddable controller'' for that example looks like this: describe "with mime type of otml" do it "renders the requested #{model_ivar_name_lambda.call} as otml without error" do The beginning of the shared_examples group looks like this: http://github.com/stepheneb/rigse/blob/master/spec/support/embeddable_controller_helper.rb shared_examples_for ''an embeddable controller'' do integrate_views controller_class_lambda = lambda { self.send(:described_class) } model_class_lambda = lambda { controller_class_lambda.call.name[/(.*)Controller/, 1].singularize.constantize } model_ivar_name_lambda = lambda { model_class_lambda.call.name.delete_module.underscore_module } def with_tags_like_an_otml(model_name) self.send("with_tags_like_an_otml_#{model_name}".to_sym) end before(:each) do @model_class = model_class_lambda.call @model_ivar_name = model_ivar_name_lambda.call unless instance_variable_defined?("@#{@model_ivar_name}".to_sym) @model_ivar = instance_variable_set("@#{@model_ivar_name}", Factory.create(@model_ivar_name)) end end The method in the controller spec: with_tags_like_an_otml_data_collector is used in the shared_examples group later like this: with_tag(''library'') do with_tags_like_an_otml(@model_ivar_name) end
David Chelimsky
2010-May-11 05:47 UTC
[rspec-users] questions about meta-programming in a shared_examples group
Hi Stephen, On May 10, 2010, at 8:48 PM, Stephen Bannasch wrote:> I''ve created a shared_examples group that helps me dry up the testing of a large set of similar rails controllers. > > These controllers have an html interface but mostly what I am testing with the shared_examples group is the rendering of four different forms of xml that relate to running a dynamically created Java Web Start jnlp. > > The html reports when running one of the controller specs looks like this: > > Embeddable::DataCollectorsController GET show with mime type of otml > renders the requested data_collector as otml without error > > Here''s an example of what one of the controller specs looks like: > > http://github.com/stepheneb/rigse/blob/master/spec/controllers/embeddable/data_collectors_controller_spec.rb > > require ''spec_helper'' > > describe Embeddable::DataCollectorsController do > > it_should_behave_like ''an embeddable controller'' > > def with_tags_like_an_otml_data_collector > with_tag(''OTDataCollector'') do > with_tag(''source'') do > with_tag(''OTDataGraphable'') do > with_tag(''dataProducer'') > end > end > with_tag(''xDataAxis'') do > with_tag(''OTDataAxis'') > end > with_tag(''yDataAxis'') do > with_tag(''OTDataAxis'') > end > end > end > > end > > I love how clearly each controller spec reads now and how the part that is different in the otml rendering stands out. > > But I wondered if the way I am using lambdas in the shared_examples helper is fragile and might break if internals in rspec change. The meta-programming I did to get some of this to work seemed a bit messy and I was wondering if there was a simpler way.The most obvious problem is that "have_tag" and "with_tag" will not be supported in rspec-rails-2. I haven''t looked at it in a while, but you may want to take a look at the assert2 gem. It''s mostly focused on test/unit assertions, but there is an rspec matcher named be_html_with that offers a nice dsl for something close to what you''re trying to do. Check the bottom of http://groups.google.com/group/merb/browse_thread/thread/3588d3f75fa0e65c.> The describe statement in the shared_examples_for ''an embeddable controller'' for that example looks like this: > > describe "with mime type of otml" do > it "renders the requested #{model_ivar_name_lambda.call} as otml without error" do > > The beginning of the shared_examples group looks like this: > > http://github.com/stepheneb/rigse/blob/master/spec/support/embeddable_controller_helper.rb > > shared_examples_for ''an embeddable controller'' do > integrate_views > > controller_class_lambda = lambda { > self.send(:described_class) > } > model_class_lambda = lambda { > controller_class_lambda.call.name[/(.*)Controller/, 1].singularize.constantize > } > model_ivar_name_lambda = lambda { > model_class_lambda.call.name.delete_module.underscore_module > } > > def with_tags_like_an_otml(model_name) > self.send("with_tags_like_an_otml_#{model_name}".to_sym) > end > > before(:each) do > @model_class = model_class_lambda.call > @model_ivar_name = model_ivar_name_lambda.call > unless instance_variable_defined?("@#{@model_ivar_name}".to_sym) > @model_ivar = instance_variable_set("@#{@model_ivar_name}", > Factory.create(@model_ivar_name)) > end > end > > > The method in the controller spec: with_tags_like_an_otml_data_collector is used in the shared_examples group later like this: > > with_tag(''library'') do > with_tags_like_an_otml(@model_ivar_name) > end > > _______________________________________________ > rspec-users mailing list > rspec-users at rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users