I have the following Chef recipe:
# recipes/default.rb
include_recipe 'my-cookbook::another_recipe'
execute 'Do some stuff' do
command "echo some stuff"
action :run
end
template "my_dir/my_file.txt" do
source "my_file.txt.erb"
owner 'myuser'
group 'mygroup'
notifies :restart, resources(:service => 'my-service'), :delayed
end
and another recipe
# recipes/another_recipe.rb
service 'my-service' do
start_command "my-service start"
stop_command "my-service stop"
supports :start => true, :stop => true
action :nothing
end
Now i want to write a Chefspec unit test to the default
recipe in isolation. So i wrote this:
# spec/unit/recipes/default_spec.rb
require 'rspec/core'
require 'chefspec'
describe 'my-cookbook::default' do
let(:chef_run) { ChefSpec::SoloRunner.converge(described_recipe) }
before do
allow_any_instance_of(Chef::Recipe).to receive(:include_recipe).with('my-cookbook::another_recipe')
end
it "Does the stuff" do
expect(chef_run).to run_execute("echo some stuff")
end
end
How do i create a dummy of the service defined in another_recipe
to prevent this happening:
11: group 'mygroup'
12>> notifies :restart, resources(:service => 'my-service'), :delayed
13: end
...
Failure/Error: let(:chef_run) { ChefSpec::SoloRunner.converge(described_recipe) }
Chef::Exceptions::ResourceNotFound:
Cannot find a resource matching service[my-service] (did you define it first?)
I know that this is probably a bad design and a fairly simple newbie question, but i'm really stuck here and my situation is this:
default
recipe, so i thought to add a few unit tests to verify that my modifications work and do not break existing functionalityanother_recipe
) as much as possibleanother_recipe
then i'd need to mock and set too many other things it needsThanks :) k6ps
You should allow the another_recipe to be in run and do the necessary for it to converge. If not you can't really trust your test as they're not done against what will happen in a run.
Well you may add a "mockers recipe" in your cookbook which will define no-ops resources you need to test your recipe without too much stub/mock calls.
Lets say it's called 'spec-receipe.rb' and it looks like:
service 'my-service' do
action :nothing
end
Then you run your tests including this 'spec-recipe' like this:
let(:chef_run) { ChefSpec::SoloRunner.converge('my_cookbook::spec-recipe',described_recipe) }
Another way could be to include_recipe 'my_cookbook::spec-recipe' if defined?(ChefSpec)
so this recipe would be included only in a chefspec run and not in normal run and you don't have to specify it in the runner declaration.