【问题标题】:How to test puts in rspec如何在 rspec 中测试放置
【发布时间】:2013-07-17 20:11:37
【问题描述】:

我想做的是在命令行运行ruby sayhello.rb,然后接收Hello from Rspec

我有这个:

class Hello
  def speak
    puts 'Hello from RSpec'
  end
end

hi = Hello.new #brings my object into existence
hi.speak

现在我想在 rspec 中编写一个测试来检查命令行输出实际上是“Hello from RSpec” 而不是“我喜欢 Unix”

不工作。我目前在我的 sayhello_spec.rb 文件中有这个

require_relative 'sayhello.rb' #points to file so I can 'see' it

describe "sayhello.rb" do
  it "should say 'Hello from Rspec' when ran" do        
    STDOUT.should_receive(:puts).with('Hello from RSpec')    
  end
end

另外,我需要在我的 RSPEC 中实际查看测试应该是什么样子。

【问题讨论】:

    标签: rspec


    【解决方案1】:

    我认为最好的方法是使用 rspec build in output matcher https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/output-matcher

    例如, 这是你的课

    class MakeIt
      def awesome(text)
        puts "Awesome #{text}"
      end
    end
    

    和你的测试

    describe MakeIt do
      describe '#awesome' do
        it 'prints awesome things' do
          expect do
            MakeIt.new.awesome('tests')
          end.to output('Awesome tests').to_stdout
        end
    
        it 'does not print not awesome things' do
          expect do
            MakeIt.new.awesome('tests')
          end.to_not output('Not awesome tests').to_stdout
        end
      end
    end
    

    不错,干净整洁!

    【讨论】:

    • 您知道是否有任何方法可以使用 contains 而不是完全相同的方法吗?
    • @AlexandreAmadodeCastro 有点晚了,但你可以使用expect(...).to output(a_string_including('xxx')).to_stdoutthis cheatsheet
    【解决方案2】:

    根据之前的答案/cmets,使用新语法的解决方案不带 gem 如下所示:

    describe "sayhello.rb" do
      it "should say 'Hello from Rspec' when run" do        
        expect(STDOUT).to receive(:puts).with('Hello from RSpec')
        require_relative 'sayhello.rb'  # load/run the file 
      end
    end
    

    【讨论】:

      【解决方案3】:

      您是在进入测试块之前执行代码,因此没有达到预期。您需要在设置期望后在测试块中运行代码(例如,将require_relative 语句移到STDOUT.... 语句之后),如下所示:

      describe "sayhello.rb" do
        it "should say 'Hello from Rspec' when ran" do        
          STDOUT.should_receive(:puts).with('Hello from RSpec')
          require_relative 'sayhello.rb' #load/run the file 
        end
      end
      

      【讨论】:

      • RSpec 不需要知道(即访问)sayhello.rb 中的代码。该规范只是对 Ruby 内置的STDOUT.puts 寄予厚望。在加载并运行sayhello.rb(即required)后满足预期。
      • 这与新的 RSpec 语法相同:expect(STDOUT).to receive(:puts).with("Hello from RSpec")
      【解决方案4】:

      您可以使用 Rails 的 active_support 库解决此问题,该库添加了一个 capture 方法:

      require 'active_support/core_ext/kernel/reporting'
      require_relative 'sayhello'
      
      describe Hello do
        it "says 'Hello from RSpec' when ran" do
          output = capture(:stdout) do
            hi = Hello.new
            hi.speak
          end
          expect(output).to include 'Hello from RSpec'
        end
      end
      

      【讨论】:

      【解决方案5】:

      有点类似于 bswinnerton 的回答,可以捕获puts 输出,然后针对捕获的输出进行测试,而无需使用依赖于库的capture 方法(有人提到在 Rails 5 中已弃用该方法)。

      Ruby 有一个名为$stdout 的全局变量,默认情况下由常量STDOUT 填充。 STDOUT 是将数据发送到 ruby​​ 进程的标准输出流(不确定“流”是否是正确的术语)。基本上在幼稚的情况下STDOUT.puts("foo") 将导致“foo\n”出现在您的终端窗口中。 $stdout.puts("foo") 会做同样的事情,因为 $stdout 变量名指的是 STDOUT 除非你重新分配它(这里的关键点)。最后puts("foo")$stdout.puts("foo") 的语法糖。

      然后的策略是将$stdout 重新分配给本地IO 实例,您可以在运行代码后检查该实例,以查看“Hello from RSpec”是否出现在其内容中。

      这是如何工作的:

      describe "sayhello.rb" do
        it "should say 'Hello from Rspec' when ran" do        
          $stdout = StringIO.new
      
          # run the code
          # (a little funky; would prefer Hello.new.speak here but only changing one thing at a time)
          require_relative 'sayhello.rb' 
      
          $stdout.rewind   # IOs act like a tape so we gotta rewind before we play it back  
      
          expect($stdout.gets.strip).to eq('Hello from Rspec')
        end
      end
      

      【讨论】:

      • 这个方法可以用来检查多个stdout消息吗? (与检查一个的其他答案相比)
      • @matrim_c:我知道你已经晚了,但为其他来这里的人回答这个问题。是的,您可以使用它来测试多个标准输出消息。 StringIO 对象就像一个文件,有多行。 gets 是读取单行的命令(包括换行符\n),然后将读取头移动到下一行的第一个字符。多次调用gets 将产生这些行,按照它们与puts 一起添加的顺序。在 StringIO 上调用 read 将为您提供全部内容,包括行间的 \n 字符。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-09
      • 1970-01-01
      • 2021-07-14
      相关资源
      最近更新 更多