rspec-puppet tests fail undefined method - ruby

I'm trying to write my first rspec test for a simple puppet class. Here's the class, rspec test and results. I'm new to rspec and would like to know what I'm doing wrong here. I follow the directions here http://rspec-puppet.com/setup/ to configure rspec-puppet for these tests. Thanks.
Class example for cron module init.pp
class cron {
service { 'crond' :
ensure => running,
enable => true
}
}
Rspec Test
require '/etc/puppetlabs/puppet/modules/cron/spec/spec_helper'
describe 'cron', :type => :module do
it { should contain_class('cron') }
it do should contain_service('crond').with(
'ensure' => 'running',
'enable' => 'true'
) end
end
Results
FF
Failures:
1) cron
Failure/Error: it { should contain_class('cron') }
NoMethodError:
undefined method `contain_class' for #<RSpec::Core::ExampleGroup::Nested_1:0x00000001c66d70>
# ./cron_spec.rb:5:in `block (2 levels) in <top (required)>'
2) cron
Failure/Error: it do should contain_service('crond').with(
NoMethodError:
undefined method `contain_service' for #<RSpec::Core::ExampleGroup::Nested_1:0x00000001c867b0>
# ./cron_spec.rb:6:in `block (2 levels) in <top (required)>'
Finished in 0.00237 seconds
2 examples, 2 failures
Failed examples:
rspec ./cron_spec.rb:5 # cron
rspec ./cron_spec.rb:6 # cron

Where did you pick up the
describe 'cron', :type => :module
syntax? That may be obsolete.
With current versions of rspec-puppet, you describe
classes
defined types
functions
hosts
You basically just want to put your spec right into spec/classes/cron_spec.rb, that should do half your work for you, e.g.
# spec/classes/cron.rb
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"
describe 'cron' do
it { should contain_service('crond').with('ensure' => 'running') }
it { should contain_service('crond').with('enable' => 'true') }
end
It is good practice to have distinct tests for each attribute value, so that possible future regressions can be identified more accurately.
Do see the README.
For a nice example of a well structured module test-suite see example42's modules.

Related

Dependency Injection causing both Rspec failure and IRB failure

Note: I am a Ruby and programming novice.
I have a class called JourneyLog I am trying to get a method called start to instantiate a new instance of another class, called Journey
class JourneyLog
attr_reader :journey_class
def initialize(journey_class: Journey)
#journey_class = journey_class
#journeys = []
end
def start(station)
journey_class.new(entry_station: station)
end
end
When I go into irbi get the following issue
2.2.3 :001 > require './lib/journeylog'
=> true
2.2.3 :002 > journeylog = JourneyLog.new
NameError: uninitialized constant JourneyLog::Journey
from /Users/BartJudge/Desktop/Makers_2018/oystercard-challenge/lib/journeylog.rb:4:in `initialize'
from (irb):2:in `new'
from (irb):2
from /Users/BartJudge/.rvm/rubies/ruby-2.2.3/bin/irb:15:in `<main>'
2.2.3 :003 >
I also have the following Rspec test
require 'journeylog'
describe JourneyLog do
let(:journey) { double :journey, entry_station: nil, complete?: false, fare: 1}
let(:station) { double :station }
let(:journey_class) { double :journey_class, new: journey }
describe '#start' do
it 'starts a journey' do
expect(journey_class).to receive(:new).with(entry_station: station)
subject.start(station)
end
end
end
I get the following Rspec failure;
1) JourneyLog#start starts a journey
Failure/Error: expect(journey_class).to receive(:new).with(entry_station: station)
(Double :journey_class).new({:entry_station=>#<Double :station>})
expected: 1 time with arguments: ({:entry_station=>#<Double :station>})
received: 0 times
# ./spec/jorneylog_spec.rb:9:in `block (3 levels) in <top (required)>'
I am at a total loss on what the problem is, or where to look for some answers.
I'm assuming I'm not injecting the Journey class properly, but thats as far as I can get myself.
Could someone provide some assistance?
In the journeylog.rb file you need to load the Journey class:
require 'journey' # I guess the Journey class is defined in lib/journey.rb
In the spec file you need to pass journey_class to the JourneyLog constructor:
describe JourneyLog do
subject { described_class.new(journey_class: journey_class) }
# ...

Custom Rake task unable to be called twice in same Rakefile unike Rake::TestTask

I recently read an "older", 2009, article about how to make a Custom Rake tasks. So far it works for the first iteration, but I saw that Rake::TestTask can be called twice, so I figured I could do it, however my name attr_accessor is not picking up the symbol I'm passing to it.
require 'rake'
require 'rake/tasklib'
module Phil
class FooTask < Rake::TaskLib
attr_accessor :name
attr_accessor :data
attr_accessor :task_dependencies
def initialize(name = :task, task_dependencies)
#name = name
#data = nil
yield self if block_given?
#task_dependencies = task_dependencies
define
end
def define
desc "Run the #{#name} task"
task #name => #task_dependencies do
puts 'Some Test being Printed'
puts #data
sh 'echo blah'
end
self
end
end
end
Phil::FooTask.new :foo, [:call_me_first, :call_me_second]
task :call_me_first do
puts 'I am called first because I am a dependency'
end
task :call_me_second do
puts 'I am called second because Im also a dependency'
end
Phil::FooTask.new(:stuff) do |t|
t.data = 'I am a stuff task.'
end
The following is the results I get.
C:\Users\user01\Desktop
λ rake --tasks
rake foo # Run the foo task
rake stuff # Run the stuff task
C:\Users\user01\Desktop
λ rake foo
I am called first because I am a dependency
I am called second because Im also a dependency
Some Test being Printed
echo blah
blah
C:\Users\user01\Desktop
λ rake stuff --trace
** Invoke stuff (first_time)
rake aborted!
Don't know how to build task '{}' (see --tasks)
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/task_manager.rb:58:in `[]'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/task.rb:61:in `lookup_prerequisite'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/task.rb:57:in `block in prerequisite_tasks'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/task.rb:57:in `map'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/task.rb:57:in `prerequisite_tasks'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/task.rb:214:in `invoke_prerequisites'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/task.rb:193:in `block in invoke_with_call_chain'
C:/tools/ruby23/lib/ruby/2.3.0/monitor.rb:214:in `mon_synchronize'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/task.rb:187:in `invoke_with_call_chain'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/task.rb:180:in `invoke'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/application.rb:152:in `invoke_task'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/application.rb:108:in `block (2 levels) in top_level'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/application.rb:108:in `each'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/application.rb:108:in `block in top_level'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/application.rb:117:in `run_with_threads'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/application.rb:102:in `top_level'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/application.rb:80:in `block in run'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/application.rb:178:in `standard_exception_handling'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/lib/rake/application.rb:77:in `run'
C:/tools/ruby23/lib/ruby/gems/2.3.0/gems/rake-12.0.0/exe/rake:27:in `<top (required)>'
C:/tools/ruby23/bin/rake:22:in `load'
C:/tools/ruby23/bin/rake:22:in `<main>'
Tasks: TOP => stuff
I'm not sure why the Rake task is failing. Even from reading the Rake's TestTask code, it seems I'm doing mostly everything correctly. I'll also say that I'm not a professional on Ruby and all the little tricks.
Keep arguments with default value at the end in method declaration!
The reason rake stuff is raising error is because of your Phil::FooTask.new(:stuff) do |t| call. Your initialize method expects two arguments. The error is in your declaration of the constructor where you've declared name = :task which has a default value of :task. However, the second parameter task_dependencies is expected. It is the second parameter that you're missing when initializing task with name :stuff.
Modify your initialize method declaration as follows:
def initialize(name = :task, task_dependencies = [])
Then you should see correct tasks when invoking rake -T:
rake foo # Run the foo task
rake stuff # Run the stuff task

If I'm testing an rspec extension, how do I suppress the results of tests which fail as part of the test?

I'm trying to write specs for an extension to rspec.
This is the gist of what I'm trying to test:
require 'rspec-let-and-after-extension'
RSpec.describe "let(...).and_after" do
it 'is called if the `let` is invoked even if the example fails' do
call_order = []
RSpec.describe do
let(:foo) { }.and_after { call_order << :and_after }
it { foo; call_order << :example; raise 'failed!' }
end.run
expect(call_order).to eq [:example, :and_after]
end
end
One of the important behaviours is that if running the example fails, the cleanup code still runs. So I test this by recording the order of the calls and raising an exception from the example.
Problem is, when I run it, it sees this block as a second example, which then fails with errors:
.F
Failures:
1)
Got 0 failures and 2 other errors:
1.1) Failure/Error: it { foo; call_order << :example; raise 'failed!' }
RuntimeError:
failed!
# ./spec/spec.rb:43:in `block (4 levels) in <top (required)>'
# ./spec/spec.rb:44:in `block (2 levels) in <top (required)>'
1.2) Failure/Error: it { foo; call_order << :example; raise 'failed!' }
RuntimeError:
failed!
# ./spec/spec.rb:43:in `block (4 levels) in <top (required)>'
Finished in 0.00167 seconds (files took 0.08011 seconds to load)
2 examples, 1 failure
Failed examples:
rspec ./spec/spec.rb:43 #
As you can see, the output did have one dot, so the actual example passed. But then there is an F, because it has seen the internal example, run that, and unsurprisingly that one failed.
How do I make rspec not see this nested example as one of the examples it's supposed to run, so that this example completes with a single dot?
(If you're wondering about what the rspec devs themselves do about their tests, it looks like they use cucumber. Do they use cucumber because they couldn't figure this out either? :))
You can use the new sandboxing API (available in 3.2+).
RSpec.configure do |rspec|
rspec.around do |ex|
RSpec::Core::Sandbox.sandboxed do |config|
# re-configure any configuration defined by your extension here
# before allowing the example to run. The sandbox runs with a fresh
# config instance, which means any configuration you have set in
# `rspec-let-and-after-extension` will not apply while the example
# is running.
# config.extend MyExtensionModule
ex.run
end
end
end

Pure Ruby rspec test passes without method being defined

I have an rspec test on a pure Ruby model:
require 'spec_helper'
require 'organization'
describe Organization do
context '#is_root?' do
it "creates a root organization" do
org = Organization.new
expect { org.is_root?.to eq true }
end
end
end
My organization model looks like this:
class Organization
attr_accessor :parent
def initialize(parent = nil)
self.parent = parent
end
end
The output when running the tests:
bundle exec rspec spec/organization_spec.rb:6
Run options: include {:locations=>{"./spec/organization_spec.rb"=>[6]}}
.
Finished in 0.00051 seconds
1 example, 0 failures
When I run the test, it passes, despite the fact that the method is_root? doesn't exist on the model. I usually work in Rails, not pure Ruby, and I've never seen this happen. What is going on?
Thanks!
It should be:
expect(org.is_root?).to eq true
When you pass block to expect it is being wrapped in ExpectationTarget class (strictly speaking BlockExpectationTarget < ExpectationTarget). Since you didn't specify what you expect from this object, the block is never executed, hence no error is raised.
You are passing a block to expect, which is never being called. You can see this by setting an expectation on that block
expect { org.is_root?.to eq true }.to_not raise_error
1) Organization#is_root? creates a root organization
Failure/Error: expect { puts "HI";org.is_root?.to eq true }.to_not raise_error
expected no Exception, got #<NoMethodError: undefined method `is_root?' for #<Organization:0x007ffa798c2ed8 #parent=nil>> with backtrace:
# ./test_spec.rb:15:in `block (4 levels) in <top (required)>'
# ./test_spec.rb:15:in `block (3 levels) in <top (required)>'
# ./test_spec.rb:15:in `block (3 levels) in <top (required)>'
Or by just putting a plain raise or puts inside the block, neither of which will be called:
expect { puts "HI"; raise; org.is_root?.to eq true }
The block form is used for expecting that a piece of code raises an exception or not. The correct syntax for checking values is:
expect(org.is_root?).to eq(true)

rake spec failed, it cannot load or find constant or global variable

I create standalone rspec test script to testing existing api framework. It works pretty well, but I found problem where in the Rakefile I need to assign some value from YAML file (uri link, email) either CONSTANT or $global_var the code in the Rakefile looks like this:
require 'rubygems'
require 'bundler/setup'
require 'yaml'
require 'rspec/core/rake_task'
task :default => :spec
desc 'Running rspec test'
task :spec, :option do |t, opt|
choice = opt[:choice]
if choice == "production"
puts 'Test running on production'
VAR = YAML::load(File.read(File.expand_path("../config/prod_variable.yml", __FILE__)))
elsif choice == "development"
puts 'Test running on development'
VAR = YAML::load(File.read(File.expand_path("../config/dev_variable.yml", __FILE__)))
end
puts VAR['URI'] #=> print out the value correctly
RSpec::Core::RakeTask.new do |task|
test = Rake.application.original_dir
task.fail_on_error = false
task.rspec_opts = '--format documentation --color'
end
end
When I run the rake command on the terminal, the rspec failed find the VAR constant value. Here is the error message from rspec
Failures:
1) ApiTest Testing API platform for GET request
Failure/Error: #var = ApiTest.new(VAR['URI'] ,
NameError:
uninitialized constant VAR
# ./rspec_test/api_test/api_test_get_spec.rb:8:in `block (2 levels) in <top (required)>'
2) ApiTest Testing API platform for POST request
Failure/Error: #zat = ApiTest.new(VAR['URI'] ,
NameError:
uninitialized constant VAR
# ./rspec_test/api_test/api_test_post_spec.rb:7:in `block (2 levels) in <top (required)>'
Is there any idea how to get this works? I need to get value from VAR constant or global variable, but seems ruby failed to assign the value.
If opt[:choice] is neither "production" nor "development", VAR is undefined in your code.

Resources