I have created a very simple custom resource in Chef, and inside that resource is some simple logic. The logic in question calls out to some custom helper methods.
I can build the resource, and execute it as part of a recipe - but if I would like to unit test the behaviour within the resource itself to ensure the flow is correct. As such, I want to be able to mock the behaviour of those helper functions so that I can direct the resource behaviour. Unfortunately, I can't get this to work.
My recipe looks like this:
my_resource 'executing' do
action :execute
end
The resource looks like this:
action :execute do
if my_helper?(node['should_be_true'])
converge_by "Updating" do
my_helper_method
end
end
end
action_class do
include CustomResource::Helpers
end
The functions are simple:
module CustomResource
module Helpers
def my_helper?(should_be_true)
should_be_true
end
def my_helper_method
hidden_method
end
def hidden_method
3
end
end
end
When I try to mock the behaviour of these in my ChefSpec tests, I get errors:
it 'executes' do
allow(CustomResource::Helpers).to receive(:my_helper?).and_return(true)
expect(CustomResource::Helpers).to receive(:my_helper_method)
expect { chef_run }.to_not raise_error
end
Failure/Error: expect(CustomResource::Helpers).to receive(:my_helper_method)
(CustomResource::Helpers).my_helper_method(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
Any ideas what I'm doing wrong in my mocking?
Thanks in advance!
Managed to make this work by changing the mocking method... Those module functions are added into the action_class, and therefore at runtime they are methods on that specific instance of the resource's ActionClass. Not sure if my solution is right/ideal - but it does work:
include CustomResource::Helpers
<snip>
it 'executes' do
allow_any_instance_of(Chef::Resource::ActionClass).to receive(:my_helper?).and_return(true)
expect_any_instance_of(Chef::Resource::ActionClass).to receive(:my_helper_method)
expect { chef_run }.to_not raise_error
end
I did look into avoiding the 'any instance of' mock, but then I got into problems and gave up - clearly the ActionClass has a lot of behaviour that I don't want to have to worry about.