ChefSpec测试报错:局部变量variable未定义问题求助
解决ChefSpec测试中"local variable 'variable' is not defined"错误
咱们一步步来排查和修复这个问题:
1. 先修复Recipe里的语法错误
首先看你Recipe里的only_if条件,有个括号没闭合,这会导致Recipe本身执行就有问题:
# 原错误代码 only_if { ::File.exist?('/mypath/'+variable[:myserver) } # 修复后 only_if { ::File.exist?('/mypath/' + variable[:myserver]) }
2. 解决Spec里的variable未定义问题
报错的核心是Spec代码里的variable[:appserver_profile]没有定义——Spec上下文和Recipe上下文是完全隔离的,你不能直接在Spec里引用Recipe里的局部变量。这里分两种常见情况处理:
情况A:variable是Recipe里的Node属性
如果Recipe里的variable其实是Node属性(比如你是用node['your_cookbook']['some_key']定义的),那你需要在Spec里先设置这个Node属性,再引用它:
修改后的Spec代码示例:
require 'spec_helper' describe 'cookbook::myserver' do # 先定义你需要的服务器名称 let(:target_server) { 'AppSrv01' } before do # 设置Node属性,对应Recipe里的variable stub_node['your_cookbook']['appserver_profile'] = target_server allow(File).to receive(:exist?).and_call_original # 用定义好的变量拼接路径,避免未定义错误 allow(File).to receive(:exist?).with("/mypath/#{target_server}").and_return(true) end context 'When all attributes are default, on Ubuntu 16.04' do let(:chef_run) do runner = ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '16.04') do |node| # 也可以在这里直接设置Node属性 node.normal['your_cookbook']['appserver_profile'] = target_server end runner.converge(described_recipe) end it 'converges successfully' do expect { chef_run }.to_not raise_error end it 'stops the Server' do expect(chef_run).to run_execute('stop Server').with( user: '123', group: 'ad', live_stream: true ) # 注意:你原来的测试里写的是run_execute('myserver'),但Recipe里的execute资源名是'stop Server',这里必须对应上! end end end
情况B:variable是Recipe里的局部变量
如果variable是Recipe里的局部变量(比如variable = { myserver: 'foo' }),那Spec里没法直接访问这个变量。你有两个选择:
- 方案1:把局部变量改成Node属性,这样就能用上面的方法在Spec里设置和引用;
- 方案2:直接在Spec里模拟对应的具体路径,不用拼接变量:
allow(File).to receive(:exist?).with('/mypath/your_actual_server_name').and_return(true)
3. 额外的小问题提醒
你测试里的run_execute('myserver')和Recipe里的execute资源名'stop Server'不匹配,这会导致测试失败,记得改成完全一致的名称。
内容的提问来源于stack exchange,提问作者Briankurt
相关产品推荐
相关产品推荐

