1

所以我正在尝试为我的一个厨师食谱编写一个单元测试(通过 ChefSpec),但我得到了一些奇怪的行为。

我有问题的配方包括 rvm::system_install 配方,显然这会导致 ChefSpec 出现问题:

Failures:

1) theoracle::prereqs installs libyaml libyaml-devel sqlite-devel
 Failure/Error: let(:chef_run) { ChefSpec::Runner.new.converge('theoracle::prereqs')}
 NoMethodError:
   undefined method `each' for nil:NilClass
 # /Users/jdoe/workspace/cookbooks/rvm/libraries/chef_rvm_recipe_helpers.rb:44:in `install_pkg_prereqs'
 # /Users/jdoe/workspace/cookbooks/rvm/recipes/system_install.rb:29:in `from_file'
 # ./recipes/prereqs.rb:22:in `from_file'
 # ./spec/unit/recipes/prereqs_spec.rb:6:in `block (2 levels) in <top (required)>'
 # ./spec/unit/recipes/prereqs_spec.rb:15:in `block (2 levels) in <top (required)>'

有问题的代码段:

/Users/jdoe/workspace/cookbooks/rvm/libraries/chef_rvm_recipe_helpers.rb:

41:        def install_pkg_prereqs(install_now = node.recipe?("rvm::gem_package"))
42:          return if mac_with_no_homebrew
43:
44>>         node[:rvm][:install_pkgs].each do |pkg|
45:            p = package pkg do

这就是我的测试的样子:

require 'spec_helper'
describe 'theoracle::prereqs' do
  let(:chef_run) { ChefSpec::Runner.new.converge('theoracle::prereqs')}

  it 'installs libyaml libyaml-devel sqlite-devel' do
    %W( libyaml libyaml-devel sqlite-devel ).each do |pkg|
      expect(chef_run).to_install_package(pkg)
    end
  end
end

这是theoracle::prereqs食谱(部分):

%W( libyaml libyaml-devel sqlite-devel ).each do |pkg|
  package pkg do
    action :install
  end
end

include_recipe 'rvm::system_install'
4

1 回答 1

1

这是正在发生的事情:

node[:rvm][:install_pkgs]

正在回归nil。因此,您正在调用nil.each并获得异常。不幸的是,有很多可能性可以解释为什么该属性可能是nil.

依赖

在您的食谱中,您是否添加了对您的食谱theoracle的依赖?rvmmetadata.rb

depends 'rvm'

如果没有这一行,Chef 将不会加载 RVM 食谱(因此不会加载其属性),从而导致install_pkgs属性为nil.

默认属性(最有可能)

如果您查看说明书中用于确定该属性值的代码chef-rvm您会发现它node[:rvm][:install_pkgs]仅在以下条件下设置:

case platform
when "redhat","centos","fedora","scientific","amazon"
  node.set['rvm']['install_pkgs']   = %w{sed grep tar gzip bzip2 bash curl git}
  default['rvm']['user_home_root']  = '/home'
when "debian","ubuntu","suse"
  node.set['rvm']['install_pkgs']   = %w{sed grep tar gzip bzip2 bash curl git-core}
  default['rvm']['user_home_root']  = '/home'
when "gentoo"
  node.set['rvm']['install_pkgs']   = %w{git}
  default['rvm']['user_home_root']  = '/home'
when "mac_os_x", "mac_os_x_server"
  node.set['rvm']['install_pkgs']   = %w{git}
  default['rvm']['user_home_root']  = '/Users'
end

在 ChefSpec 的情况下,所有 Ohai 数据(设置platform密钥的内容)都被模拟以允许控制此行为。最有可能的是,ChefSpec 将其平台报告为chefspec,并且由于该case语句没有默认块,因此属性为nil

要解决此问题,请告诉 ChefSpec 表现得像一个特定的操作系统:

ChefSpec::Runner.new(platform: 'ubuntu', version: '12.04')

或者在测试中手动设置属性:

let(:chef_run) do
  ChefSpec::Runner.new do |node|
    node.set['rvm']['install_pkgs'] = %w(whatever)
  end.converge(described_recipe)
end
于 2014-08-13T17:36:20.037 回答