Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing STDOUT output in Rspec

Tags:

ruby

rspec

rspec2

I am trying to build a spec for this statement. It is easy with 'puts'

print "'#{@file}' doesn't exist: Create Empty File (y/n)?" 
like image 750
user2292710 Avatar asked May 12 '13 11:05

user2292710


2 Answers

If your goal is only to be able to test this method, I would do it like this:

class Executable   def initialize(outstream, instream, file)     @outstream, @instream, @file = outstream, instream, file   end    def prompt_create_file     @outstream.print "'#{@file}' doesn't exist: Create Empty File (y/n)?"   end end   # when executing for real, you would do something like # Executable.new $stdout, $stdin, ARGV[0]  # when testing, you would do describe 'Executable' do   before { @input = '' }   let(:instream)   { StringIO.new @input }   let(:outstream)  { StringIO.new }   let(:filename)   { File.expand_path '../testfile', __FILE__ }   let(:executable) { Executable.new outstream, instream, filename }    specify 'prompt_create_file prompts the user to create a new file' do     executable.prompt_create_file     outstream.string.should include "Create Empty File (y/n)"   end end 

However, I want to point out that I would not test a method like this directly. Instead, I'd test the code that uses it. I was talking with a potential apprentice yesterday, and he was doing something very similar, so I sat down with him, and we reimplemented a portion of the class, you can see that here.

I also have a blog that talks about this kind of thing.

like image 23
Joshua Cheek Avatar answered Sep 24 '22 00:09

Joshua Cheek


RSpec 3.0+

RSpec 3.0 added a new output matcher for this purpose:

expect { my_method }.to output("my message").to_stdout expect { my_method }.to output("my error").to_stderr 

Minitest

Minitest also has something called capture_io:

out, err = capture_io do   my_method end  assert_equals "my message", out assert_equals "my error", err 

RSpec < 3.0 (and others)

For RSpec < 3.0 and other frameworks, you can use the following helper. This will allow you to capture whatever is sent to stdout and stderr, respectively:

require 'stringio'  def capture_stdout(&blk)   old = $stdout   $stdout = fake = StringIO.new   blk.call   fake.string ensure   $stdout = old end  def capture_stderr(&blk)   old = $stderr   $stderr = fake = StringIO.new   blk.call   fake.string ensure   $stderr = old end 

Now, when you have a method that should print something to the console

def my_method   # ...   print "my message" end 

you can write a spec like this:

it 'should print "my message"' do   printed = capture_stdout do     my_method # do your actual method call   end    printed.should eq("my message") end 
like image 144
Patrick Oscity Avatar answered Sep 23 '22 00:09

Patrick Oscity