Test for warnings using RSpec

后端 未结 3 885
暗喜
暗喜 2021-01-17 23:32

Is it somehow possible to test warnings i Ruby using RSpec?

Like this:

class MyClass
  def initialize
    warn \"Something is wrong\"
  end
end

it \         


        
相关标签:
3条回答
  • 2021-01-17 23:35

    There is a good article with custom expectation which solves exactly your problem: http://greyblake.com/blog/2012/12/14/custom-expectations-with-rspec/

    So it would like:

    expect { MyClass.new }.to write("Something is wrong").to(:error)
    

    Base on that article you can create you own expectation to use it like this:

    expect { MyClass.new }.to warn("Something is wrong")
    
    0 讨论(0)
  • 2021-01-17 23:38

    This is my solution, I define a custom matcher has_warn

    require 'rspec'
    require 'stringio'
    
    module CustomMatchers
      class HasWarn
        def initialize(expected)
          @expected = expected
        end
    
        def matches?(given_proc)
          original_stderr = $stderr
          $stderr = StringIO.new
          given_proc.call
          @buffer = $stderr.string.strip
          @expected.include? @buffer.strip
        ensure
          $stderr = original_stderr
        end
    
        def supports_block_expectations?
          true
        end
    
        def failure_message_generator(to)
          %Q[expected #{to} get message:\n#{@expected.inspect}\nbut got:\n#{@buffer.inspect}]
        end
    
        def failure_message
          failure_message_generator 'to'
        end
    
        def failure_message_when_negated
          failure_message_generator 'not to'
        end
    
      end
    
      def has_warn(msg)
        HasWarn.new(msg)
      end
    end
    

    now you can use this function as follow after include the CustomMatchers:

    expect{ MyClass.new }.to has_warn("warning messages")
    
    0 讨论(0)
  • 2021-01-17 23:43

    warn is defined in Kernel, which is included in every object. If you weren't raising the warning during initialization, you could specify a warning like this:

    obj = SomeClass.new
    obj.should_receive(:warn).with("Some Message")
    obj.method_that_warns
    

    Spec'ing a warning raised in the initialize method is quite more complex. If it must be done, you can swap in a fake IO object for $stderr and inspect it. Just be sure to restore it after the example

    class MyClass
      def initialize
        warn "Something is wrong"
      end
    end
    
    describe MyClass do
      before do
        @orig_stderr = $stderr
        $stderr = StringIO.new
      end
    
      it "warns on initialization" do
        MyClass.new
        $stderr.rewind
        $stderr.string.chomp.should eq("Something is wrong")
      end
    
      after do
        $stderr = @orig_stderr
      end
    end
    
    0 讨论(0)
提交回复
热议问题