ChefSpecを使うときに地味に面倒なのが、複数のcookbook_pathがあるときのその指定。ChefRunner.new
するときに指定できますが、これだとspecファイル毎に指定なのでとっても面倒。
実際に実行するのはrakeからという方も多いと思うので、rakeから実行するspecファイル全部にcookbook_path指定をする方法。
はじめに
ここではcookbooks
、site-cookbooks
の2つのディレクトリにcookbookが分かれて保存されており、rake rspec
で実行できる状態になっているものとします。テスト対象はsite-cookbooks
のみ。
require "rspec/core/rake_task"
TOPDIR=File.expand_path(File.dirname(__FILE__))
desc "execute all chefspec test"
task :rspec do
RSpec::Core::RakeTask.new(:rspec) do |t|
t.pattern = 'site-cookbooks/*/spec/*_spec.rb'
t.rspec_opts = ['-c']
end
end
spec_helperの作成
Rubyの場合、オープンクラスという機能を使って、gemで配られているライブラリのコードを書き換える事ができます。ChefSpec::ChefRunner
ではvendor/cookbooks
,test/cookbooks
, spec/cookbooks
の3つは存在すれば追加してくれるようですが、今回のケースみたいに特定のサイトで使うChef全部のリポジトリを想定したものではないので当てはまりません。
なので、この3つのパスを追加している部分をオープンクラスで書き換えてしまいます。
require 'chefspec/chef_runner'
TOPDIR=File.expand_path(File.dirname(__FILE__))
module ChefSpec
class ChefRunner
remove_method :cookbook_paths
def cookbook_paths
["#{TOPDIR}/cookbooks", "#{TOPDIR}/site-cookbooks"]
end
end
end
ここでは元あったcookbook_paths
の定義を削除して、都合のいいcookbook_paths
に差し替えています。
Rakefileの修正
先ほどのspec_helperを有効にするには、ChefSpec実行前にこのコードが読み込まれている必要があります。なので、ChefSpec(RSpec)実行時にこのファイルを必ず読み込むように、以下のようにRakefileを修正します。
require "rspec/core/rake_task"
TOPDIR=File.expand_path(File.dirname(__FILE__))
desc "execute all chefspec test"
task :rspec do
RSpec::Core::RakeTask.new(:rspec) do |t|
t.pattern = 'site-cookbooks/*/spec/*_spec.rb'
t.rspec_opts = ['-c']
t.ruby_opts = ["-r", "#{TOPDIR}/spec_helper.rb"]
end
end
追加したのはt.ruby_opts = ["-r", "#{TOPDIR}/spec_helper.rb"]
です。これによってChefSpecを実行する際は必ずspec_helper.rbを読んでから実行するようになります。
補足
上記を組み込んだ場合は「cookbook_pathのデフォルト値がspec_helperで指定したものになる」だけなので、ChefRunner.new(:cookbook_path => paths)
として渡した場合はそちらが優先されます。また、これはcookbook_path以外にも応用可能なので、それでコードの重複を減らすこともできます。