代码之家  ›  专栏  ›  技术社区  ›  k6ps

如何创建在另一个配方中定义的虚拟资源,而不在测试运行中包含其他配方?

  •  4
  • k6ps  · 技术社区  · 10 年前

    我有以下厨师食谱:

    # 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
    

    和另一个食谱

    # 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
    

    现在我想写一个Chefspec单元测试到 default 隔离配方。所以我写了这个:

    # 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
    

    如何创建中定义的服务的虚拟对象 another_recipe 为了防止这种情况发生:

     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?)
    

    我知道这可能是一个糟糕的设计和一个相当简单的新手问题,但我真的被困在这里,我的情况是:

    • 我有几个月的厨师经验,但除此之外没有Ruby经验
    • 这是一个最初在没有任何单元测试的情况下编写的生产代码
    • 真正的代码包含更多的内容,这里的这些代码片段只是特定问题的一个模型
    • 我有一个任务要修改 违约 配方,所以我想添加一些单元测试,以验证我的修改是否有效,并且不会破坏现有功能
    • 此时,我希望避免修改任何其他文件(即 另一个收件人 )尽可能多
    • 如果我让测试也运行 另一个收件人 那么我就需要模仿和设置太多其他需要的东西

    谢谢:) k6磅

    3 回复  |  直到 10 年前
        1
  •  3
  •   Tensibai    10 年前

    我的观点:

    您应该让另一个_recipe运行,并执行必要的操作使其收敛。如果没有,你就不能真正信任你的测试,因为他们没有针对跑步中会发生的事情进行测试。

    无论如何都要设法回答您的问题:

    好吧,你可以在你的食谱中添加一个“mockers配方”,它将定义不需要太多存根/模拟调用就可以测试你的配方的操作资源。

    让我们假设它叫做“specreceipe.rb”,它看起来像:

    service 'my-service' do
      action :nothing
    end
    

    然后你运行测试,包括如下“规范配方”:

    let(:chef_run) { ChefSpec::SoloRunner.converge('my_cookbook::spec-recipe',described_recipe) }
    

    另一种方法是 include_recipe 'my_cookbook::spec-recipe' if defined?(ChefSpec) 因此,该配方将仅包含在chefspec运行中,而不包含在正常运行中,您不必在runner声明中指定它。

        2
  •  1
  •   Marcel Tricolici    9 年前
    describe 'mycookbook::default' do
      context 'something' do
        let(:solo) do
          ChefSpec::SoloRunner.new
        end 
    
        let(:chef_run) do
          solo.converge(described_recipe) do
            solo.resource_collection.insert(
                    Chef::Resource::Service.new('apache2', solo.run_context))
          end 
        end 
    
        it 'runs without errors' do
          allow_any_instance_of(Chef::Recipe).to receive(:include_recipe)
          chef_run
        end 
      end 
    end
    
        3
  •  0
  •   nshemonsky    9 年前

    另一种方法是在配方中包含begin/recue,以便在必要时将服务添加到资源集合中。默认操作是:什么都不做,所以您只需要将其列在救援块中。

    begin
      svc = resources('service[my-service]')
    rescue
      svc = service 'my-service'
    end
    
    template "my_dir/my_file.txt" do
      source "my_file.txt.erb"
      owner 'myuser'
      group 'mygroup'
      notifies :restart, svc, :delayed
    end