I'm trying to create a spec test for the following recipe code:
if node.attribute?(node['tested_cookbook']['some_attribute'])
include_recipe('tested_cookbook::first')
else
include_recipe('tested_cookbook::second')
I have the following spec for this:
require 'spec_helper'
describe 'tested_cookbook::default' do
let(:chef_run) { ChefSpec::SoloRunner.new(platform: 'windows', version: '2008R2') do |node|
node.set['tested_cookbook']['some_attribute'] = "some_value"
end.converge(described_recipe) }
it 'includes recipe iis' do
expect(chef_run).to include_recipe('tested_cookbook::first')
end
end
The problem is that this test will always fail. How do I properly mock the outcome of 'node.attribute?' ? Thank you.
I'm not sure you can override the node object in Chefspec without monkey patching, which I think is probably more trouble than it's worth. I really almost never even see node.attribute?
used, so it may be somewhat of an anti-pattern. (Do you really care if it was set, vs. if it has a non-nil value or not?)
I would just avoid using attribute?
in the first place, e.g.
Recipe:
if node['tested_cookbook'] && node['tested_cookbook']['some_attribute'])
include_recipe('tested_cookbook::first')
else
include_recipe('tested_cookbook::second')
end
Spec:
require 'spec_helper'
describe 'tested_cookbook::default' do
let(:chef_run) { ChefSpec::SoloRunner.new(platform: 'windows', version: '2008R2') do |node|
node.set['tested_cookbook']['some_attribute'] = "some_value"
end.converge(described_recipe) }
it 'includes recipe iis' do
expect(chef_run).to include_recipe('tested_cookbook::first')
end
end
It's common practice to give these attributes a default value, too, so it would be even more idiomatic to say:
attributes/default.rb:
default['tested_cookbook']['some_attribute'] = 'second'
recipe:
include_recipe "tested_cookbook::#{node['tested_cookbook']['some_attribute']}"
And then in your spec, do the same check as before. You're using an attribute to run ::second, but allowing someone to override it to ::first. If you don't like the pattern of actually using the attribute value to include, you could make it a flag and keep your previous if-statement too.