I was having a problem yesterday with a specific rspec test that was failing for my puppet tool generate-puppetfile, and I couldn’t understand why. I was expecting an exitcode of 0
but was receiving 1
, so obviously I had an issue, but I couldn’t see the accompanying error message. When I attempted to run the command myself, it succeeded, so I was pretty sure the issue was with either argument handling by my program or more likely, the way I wrote my rspec test (spoiler: it was in my rspec!). Here’s what the rspec test looked like to start with:
context 'when creating fixtures' do let :args do 'rnelson0/certs' '--create-fixtures' end its(:exitstatus) { is_expected.to eq(0) } it 'should create .fixtures.yml' do File.exists? './.fixtures.yml' end end
Astute readers may see the problem already, but I didn’t. When I ran this test, the errors weren’t very helpful:
when creating fixtures should create .fixtures.yml exitstatus should eq 0 (FAILED - 1) Failures: 1) GeneratePuppetfile::Bin when creating fixtures exitstatus should eq 0 Failure/Error: its(:exitstatus) { is_expected.to eq(0) } expected: 0 got: 1 (compared using ==) # ./spec/generate_puppetfile/bin_spec.rb:81:in `block (3 levels) in '
Well that’s so helpful! I didn’t see the error, and running bundle exec generate-puppetfile rnelson0/certs --create-fixtures
worked without any problems. I couldn’t see the output since I had to capture it for use with other tests (see here), but I could get at it indirectly. That output is captured in the subject variable, which is tested elsewhere by looking at subject.stdout
or subject.stderr
. By adding a check against this, I won’t automatically see the output, but if the comparison fails, it shows the actual output that was expected to contain Generating .fixtures.yml
:
# Addition to tests it 'should say that fixtures have been created' do expect(subject.stdout).to include "Generating .fixtures.yml" end
# New error messages when creating fixtures should say that fixtures have been created (FAILED - 1) should create .fixtures.yml exitstatus should eq 0 (FAILED - 2) Failures: 1) GeneratePuppetfile::Bin when creating fixtures should say that fixtures have been created Failure/Error: expect(subject.stdout).to include "Generating .fixtures.yml" expected "generate-puppetfile: try 'generate-puppetfile --help' for more information." to include "Generating .fixtures.yml" # ./spec/generate_puppetfile/bin_spec.rb:83:in `block (3 levels) in ' 2) GeneratePuppetfile::Bin when creating fixtures exitstatus should eq 0 Failure/Error: its(:exitstatus) { is_expected.to eq(0) } expected: 0 got: 1 (compared using ==) # ./spec/generate_puppetfile/bin_spec.rb:81:in `block (3 levels) in '
This informed me that the arguments in my tests were not making it to generate-puppetfile properly, and after verifying how my program accepted arguments, it turned out it was the let :args do
block. I was not creating the contents as an array, so only the last argument provided actually counted. Whoops! The updated test looks like:
context 'when creating fixtures' do let :args do [ 'rnelson0/certs', '--create-fixtures', ] end its(:exitstatus) { is_expected.to eq(0) } it 'should say that fixtures have been created' do expect(subject.stdout).to include "Generating .fixtures.yml" end it 'should create .fixtures.yml' do File.exists? './.fixtures.yml' end end
Note the square brackets and commas between arguments. In hindsight, this is fairly obvious, but it was easy to miss as no error was thrown by the improper syntax. Thankfully, I was able to capture output more directly and see what the exact result was. I feel a little more capable now with rspec and I hope this helps others as well!