【问题标题】:How to write regression tests for custom Chef resources?如何为自定义 Chef 资源编写回归测试?
【发布时间】:2016-09-20 01:59:32
【问题描述】:

举个最简单的例子

# resources/novowel.rb
resource_name :novowel
property :name, String, name_property: true, regex: /\A[^aeiou]\z/

我想在spec/unit/resources/novowel_spec.rb写单元测试

  • 名称的资源“novowel”应接受“k”
  • 名称的资源“novowel”应接受“&”
  • 名称的资源“novowel”不应接受“a”
  • 名称的资源“novowel”不应接受“mm”

确保即使由于某种原因更改了正则表达式,名称属性仍然可以正常工作。

我浏览了几本顶级厨师食谱,但找不到此类测试的参考资料。

怎么做?如果这有助于完成任务,请随意提供更复杂的示例,明确子类化 Chef::Resource

更新 1: 当属性不适合 regex 时,Chef 会不会失败?显然这不应该工作:

link '/none' do
  owner  'r<oo=t'
  to     '/usr'
end

但是chef-apply (12.13.37) 并没有抱怨r&lt;oo=t 不匹配owner_valid_regex。它只是收敛,好像没有提供owner

【问题讨论】:

    标签: ruby chef-infra cookbook lwrp


    【解决方案1】:

    您将使用 ChefSpec 和 RSpec。我的所有食谱中都有示例(例如https://github.com/poise/poise-python/tree/master/test/spec/resources),但我还在普通的 ChefSpec 之上使用了一堆自定义助手,因此它可能不是很有帮助。在规范中执行内联配方代码块使其更容易。我已经开始在https://github.com/poise/poise-spec 中提取我的助手以供外部使用,但还没有完成。当前的助手在我的 Halite gem 中,请参阅那里的自述文件以获取更多信息。

    【讨论】:

    • 回答您的编辑,属性验证仅在访问属性时运行,而不是在设置时运行。这有 原因 ?
    • “访问属性”是什么意思? this question 中的类似内容?
    • ownerto 是资源属性。在提供者代码中,我们有类似new_resource.owner 的东西来获取该属性的值并对其进行处理。然后发生验证代码。因为 ChefSpec 将提供者排除在外,这可能会导致属性永远不会被访问,因此允许使用无效值。
    • 所以我可以通过 RSpec'ing 提供者来测试正则表达式?
    • 不幸的是,这里没有简单的答案。通过 ChefSpec 设置测试工具比 StackOverflow 更复杂。
    【解决方案2】:

    我们将 DSL 包装在一个小 Ruby 中,以便知道资源的 Ruby 类的名称:

    # libraries/no_vowel_resource.rb
    require 'chef/resource'
    
    class Chef
      class Resource
        class NoVowel < Chef::Resource
          resource_name :novowel
          property :letter, String, name_property: true, regex: /\A[^aeiou]\z/
          property :author, String, regex: /\A[^aeiou]+\z/
        end
      end
    end
    

    现在我们可以使用 RSpec 了

    # spec/unit/libraries/no_vowel_resource_spec.rb
    require 'spec_helper'
    
    require_relative '../../../libraries/no_vowel_resource.rb'
    
    describe Chef::Resource::NoVowel do
      before(:each) do
        @resource = described_class.new('k')
      end
    
      describe "property 'letter'" do
        it "should accept the letter 'k'" do
          @resource.letter = 'k'
          expect(@resource.letter).to eq('k')
        end
    
        it "should accept the character '&'" do
          @resource.letter = '&'
          expect(@resource.letter).to eq('&')
        end
    
        it "should NOT accept the vowel 'a'" do
          expect { @resource.letter = 'a' }.to raise_error(Chef::Exceptions::ValidationFailed)
        end
    
        it "should NOT accept the word 'mm'" do
          expect { @resource.letter = 'mm' }.to raise_error(Chef::Exceptions::ValidationFailed)
        end
      end
    
      describe "property 'author'" do
        it "should accept a String without vowels" do
          @resource.author = 'cdrngr'
          expect(@resource.author).to eq('cdrngr')
        end
    
        it "should NOT accept a String with vowels" do
          expect { @resource.author = 'coderanger' }.to raise_error(Chef::Exceptions::ValidationFailed)
        end
      end
    end
    

    【讨论】:

    • 这仅适用于 name 属性(顺便说一下,不应将其称为 :name)。
    • @coderanger 我不敢苟同。当然,您可以指定任何这样的属性。请参阅上面的扩展示例。
    • @coderanger 您能否解释一下为什么拥有名为name 的名称属性可能会有问题?
    • 啊,在定义自定义属性name 时,Chef::Resource 中的这个定义会被覆盖:property :name, String, coerce: proc { |v| v.is_a?(Array) ? v.join(", ") : v.to_s }, desired_state: false
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-23
    • 2015-03-29
    • 1970-01-01
    相关资源
    最近更新 更多