Suppress console output during RSpec tests

后端 未结 7 1112
小鲜肉
小鲜肉 2020-12-02 12:24

I am testing the class which put on the console some messages (with puts, p warnings and etc.). I am just wondering if there is any ability to suppress this output during R

相关标签:
7条回答
  • 2020-12-02 12:43

    After trying all of these examples, I ended up using this varation which does not silence or mute binding.pry

    # frozen_string_literal: true
    
    RSpec.configure do |config|
      config.before(:each) do
        allow($stdout).to receive(:puts)
        allow($stdout).to receive(:write)
      end
    end
    
    0 讨论(0)
  • 2020-12-02 12:45

    Tested with rspec-core (~> 3.4.0)

    In describe block you could do

    # spec_helper.rb
    def suppress_log_output
      allow(STDOUT).to receive(:puts) # this disables puts
      logger = double('Logger').as_null_object
      allow(Logger).to receive(:new).and_return(logger)
    end
    
    # some_class_spec.rb
    RSpec.describe SomeClass do
      before do
        suppress_log_output
      end
    end
    

    This way you have the advantage of toggling log output for specific tests. Note, this will not suppress rspec warnings, or messages from rspec.

    Another way to disable warnings coming from gems:

    add config.warnings = false to spec_helper

    If you wanted to suppress only certain logger methods, like error, info, or warn you could do

    allow_any_instance_of(Logger).to receive(:warn).and_return(nil)

    To disable warnings coming from the rspec gem

    allow(RSpec::Support).to receive(:warning_notifier).and_return(nil)

    but this is generally discouraged because it is meant as a way to let you know you are doing something smelly in your tests.

    0 讨论(0)
  • 2020-12-02 12:50

    Updated answer for Rails 5, in a one-off situation:

    before do
      RSpec::Mocks.with_temporary_scope do
        allow(STDOUT).to receive(:puts)
      end
    end
    

    You can make this into a method in spec_helper if you'll be doing this a lot.

    0 讨论(0)
  • 2020-12-02 12:51

    If you want to suppress output for a single test, there is a more concise way:

    it "should do something with printing" do
      silence_stream(STDOUT) do
        foo.print.should be_true
      end
    end
    

    You may want to change STDOUT to STDERR if your test prints an error.

    0 讨论(0)
  • 2020-12-02 12:54

    Try stubbing methods that make the output in a before block, e.g.

    before do
      IO.any_instance.stub(:puts) # globally
      YourClass.any_instance.stub(:puts) # or for just one class
    end
    

    This is explicit, so you won't miss anything you don't want to miss. If you don't care about any output and the method above doesn't work you can always stub the IO object itself:

    before do
      $stdout.stub(:write) # and/or $stderr if needed
    end
    
    0 讨论(0)
  • 2020-12-02 12:59

    I suppress puts output in my classes by redirecting $stout to a text file. That way, if I need to see the output for any reason, it is there but it doesn't muddy up my test results.

    #spec_helper.rb
    RSpec.configure do |config|
      config.before(:all, &:silence_output)
      config.after(:all,  &:enable_output)
    end
    
    public
    # Redirects stderr and stout to /dev/null.txt
    def silence_output
      # Store the original stderr and stdout in order to restore them later
      @original_stderr = $stderr
      @original_stdout = $stdout
    
      # Redirect stderr and stdout
      $stderr = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w')
      $stdout = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w')
    end
    
    # Replace stderr and stdout so anything else is output correctly
    def enable_output
      $stderr = @original_stderr
      $stdout = @original_stdout
      @original_stderr = nil
      @original_stdout = nil
    end
    

    EDIT:

    In response to the comment by @MyronMarston, it probably would be smarter to just insert the methods directly into before and after as blocks.

    #spec_helper.rb
    RSpec.configure do |config|
      original_stderr = $stderr
      original_stdout = $stdout
      config.before(:all) do 
        # Redirect stderr and stdout
        $stderr = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w')
        $stdout = File.new(File.join(File.dirname(__FILE__), 'dev', 'null.txt'), 'w')
      end
      config.after(:all) do 
        $stderr = original_stderr
        $stdout = original_stdout
      end
    end
    

    It looks a little cleaner and keeps methods off of main. Also, note that if you are using Ruby 2.0, you can use __dir__ instead of File.dirname(__FILE__).

    EDIT2

    Also it should be mentioned, that you can forward to true os /dev/null by using File::NULL as it was introduced in Ruby v 1.9.3. (jruby 1.7)

    Then the code snippet will look as following:

    #spec_helper.rb
    RSpec.configure do |config|
      original_stderr = $stderr
      original_stdout = $stdout
      config.before(:all) do
        # Redirect stderr and stdout
        $stderr = File.open(File::NULL, "w")
        $stdout = File.open(File::NULL, "w")
      end
      config.after(:all) do
        $stderr = original_stderr
        $stdout = original_stdout
      end
    end
    
    0 讨论(0)
提交回复
热议问题