Test Driven Development (TDD) is a way to write unit test before writing any actual recipe code. The test should be real and should validate what a recipe does. It should actually fail as there was no recipe developed. Once the recipe is developed, the test should pass.
ChefSpec is built on the popular RSpec framework and offers a tailored syntax for testing Chef recipe.
Creating ChefSpec
Step 1 − Create a gem file containing the chefSpec gem.
vipin@laptop:~/chef-repo $ subl Gemfile source 'https://rubygems.org' gem 'chefspec'
Step 2 − Install the gem.
vipin@laptop:~/chef-repo $ bundler install Fetching gem metadata from https://rubygems.org/ ...TRUNCATED OUTPUT... Installing chefspec (1.3.1) Using bundler (1.3.5) Your bundle is complete!
Step 3 − Create a spec directory.
vipin@laptop:~/chef-repo $ mkdir cookbooks/<Cookbook Name>/spec
Step 4 − Create a Spec
vipin@laptop:~/chef-repo $ subl cookbooks/my_cookbook/spec/default_spec.rb require 'chefspec' describe 'my_cookbook::default' do let(:chef_run) { ChefSpec::ChefRunner.new( platform:'ubuntu', version:'12.04' ).converge(described_recipe) } it 'creates a greetings file, containing the platform name' do expect(chef_run).to create_file_with_content('/tmp/greeting.txt','Hello! ubuntu!') end end
Step 5 − Validate ChefSpec.
vipin@laptop:~/chef-repo $ rspec cookbooks/<Cookbook Name>/spec/default_spec.rb F Failures: 1) <CookBook Name> ::default creates a greetings file, containing the platform name Failure/Error: expect(chef_run.converge(described_recipe)).to create_file_with_content('/tmp/greeting.txt','Hello! ubuntu!') File content: does not match expected: Hello! ubuntu! # ./cookbooks/my_cookbook/spec/default_spec.rb:11:in `block (2 levels) in <top (required)>' Finished in 0.11152 seconds 1 example, 1 failure Failed examples: rspec ./cookbooks/my_cookbook/spec/default_spec.rb:10 # my_ cookbook::default creates a greetings file, containing the platform name
Step 6 − Edit Cookbooks default recipe.
vipin@laptop:~/chef-repo $ subl cookbooks/<Cookbook Name>/recipes/default.rb template '/tmp/greeting.txt' do variables greeting: 'Hello!' end
Step 7 − Create a template file.
vipin@laptop:~/chef-repo $ subl cookbooks/< Cookbook Name>/recipes/default.rb <%= @greeting %> <%= node['platform'] %>!
Step 8 − Run the rspec again.
vipin@laptop:~/chef-repo $ rspec cookbooks/<Cookbook Name>/spec/default_spec.rb . Finished in 0.10142 seconds 1 example, 0 failures
How It Works
In order to make it work, we need to first set up the base infrastructure for using RSpec with Chef. Then we need to ChefSpec Ruby gem and the cookbook needs a directory called spec where all the tests will be saved.