Update 4 Jan 2014: The following idea is now implemented inside ChefSpec (>= 3.1.2). See Faster Specs part in Readme.
================================
This is a excerpt from an blogpost that covers this topic with some more details.
RSpec allows to extend modules with your own methods and the idea is to write method similar to let, but which will cache the results across examples too. Create a *spec_helper.rb* file somewhere in your Chef project and add the following lines there:
module SpecHelper
@@cache = {}
def shared( name, &block )
location = ancestors.first.metadata[:example_group][:location]
define_method( name ) do
@@cache[location + name.to_s] ||= instance_eval( &block )
end
end
def shared!( name, &block )
shared name, &block
before { __send__ name }
end
end
RSpec.configure do |config|
config.extend SpecHelper
end
Values from @@cache are never deleted, and you can use same names with this block, so I also use location of the usage, which looks like that: "./cookbooks/my_cookbook/spec/default_spec.rb:3". Now change let( :chef_run )
into shared( :chef_run )
in your specs:
describe "example::default" do
shared( :chef_run ) { ChefSpec::ChefRunner.new.converge described_recipe }
[...]
end
And when running the tests you will now have to include the spec_helper.rb too:
rspec --include ./relative/path/spec_helper.rb cookbooks/*/spec/*_spec.rb