Can I stub STDERR in RSpec?

I have a simple function that I would like to test (perhaps mainly to calm simplecov). Function:

module Utils
  extend self

  def blather(msg)
    msg = "=== " + msg
    STDERR.puts(msg)
    Rails.logger.debug(msg)
  end

end

The RSpec documentation for stubbing says that:

Messages can be shaded on any class, including in the main Ruby library.

But the following:

# file: spec/lib/utils_spec.rb
require 'spec_helper'
describe Utils do
  context "blather" do
    it "should print to STDERR" do
      STDERR.any_instance.should_receive(:puts).with("=== zoo")    
      Utils.blather("zoo")
    end
  end
end

... I get an error

undefined method `any_instance' for #<IO:<STDERR>>

Putting aside questions about whether this test makes sense, is it possible to drown out STDERR (class IO)? Is this not because it is a class method? Or is there a smarter strategy for such a test?

+3
source share
3 answers

First, you should usually use $stderr, not STDERR.

module Utils
  extend self

  def blather(msg)
    msg = "=== " + msg
    $stderr.puts(msg)
    Rails.logger.debug(msg)
  end

end

To answer your question, you can do the following in RSpec:

describe Utils do
  context "blather" do
    it "should print to stderr" do
      $stderr.should_receive(:puts).with("=== zoo")
      Utils.blather("zoo")
    end
  end
end

$stderr.should_receive. $stderr , , .

+6

stderr, , , puts .

$stderr ( ), STDERR const, rspec beautiful output :

expect { blather("zoo") }.to output(/=== zoo/).to_stderr

, $stderr (, , stub_const "STDERR") StringIO .string ... ( , matcher .)

+2

Duh. STDIO is not a class - it is an I / O example, so the change is:

STDERR.any_instance.should_receive(:puts).with("=== zoo")

to

STDERR.should_receive(:puts).with("=== zoo")

skips the test.

+1
source

All Articles