0

我在 Chef 中创建了一个非常简单的自定义资源,该资源内部是一些简单的逻辑。有问题的逻辑调用了一些自定义辅助方法。

我可以构建资源,并将其作为配方的一部分执行 - 但如果我想对资源本身的行为进行单元测试以确保流程正确。因此,我希望能够模拟这些辅助函数的行为,以便我可以指导资源行为。不幸的是,我无法让它工作。

我的食谱是这样的:

my_resource 'executing' do
    action :execute
end

资源如下所示:

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

功能很简单:

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

当我试图在我的 ChefSpec 测试中模拟这些行为时,我得到了错误:

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

任何想法我在嘲笑中做错了什么?

提前致谢!

4

2 回答 2

1

设法通过更改模拟方法来完成这项工作......这些模块函数被添加到action_class中,因此在运行时它们是资源ActionClass的特定实例上的方法。不确定我的解决方案是否正确/理想 - 但它确实有效:

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

我确实考虑过避免模拟的“任何实例”,但后来我遇到了问题并放弃了——显然 ActionClass 有很多我不想担心的行为。

于 2017-10-21T12:24:32.183 回答
0

不幸的是,考虑到 ChefSpec 的工作方式,这非常困难。您需要在资源的任何实例上存根它,因为那是实际的接收者。如果您可以改用模块方法,那会稍微容易一些。我认为您已经在使用require_relative您的库文件,否则代码会以不同的方式失败。但是对于自定义资源没有办法这样做,因为它们是 DSL-y 并且 Ruby 不能直接加载它们。最简单的选择通常是不测试这种东西。将代码放入检查是否设置了节点属性的辅助方法中,如果设置了则使用该值(具体取决于具体情况),然后在测试中设置它。不过,这很恶心,也很烦人,这也是 Halite 存在的部分原因。

于 2017-10-17T18:59:02.510 回答