Подтвердить что ты не робот

Как проверить, помещает ли rspec

Я хочу сделать, это запустить 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.

4b9b3361

Ответ 1

Вы выполняете свой код перед входом в тестовый блок, поэтому ожидания не выполняются. Вам нужно запустить код в тестовом блоке после установки ожиданий (например, перемещая оператор 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

Ответ 2

Вы можете решить эту проблему, используя библиотеку 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

Ответ 3

На основе предыдущих ответов/комментариев решение, использующее новый синтаксис без драгоценного камня, будет выглядеть так:

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

Ответ 4

Я думаю, что лучший способ - использовать сборку rspec в коннекторе вывода 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

Приятный, чистый и по книге!

Ответ 5

В некоторой степени похожий на ответ bswinnerton, можно записать вывод puts, а затем протестировать на захваченный вывод, не используя библиотечно-зависимый метод capture (который упоминал кто-то, устаревший в Rails 5).

Ruby имеет глобальную переменную с именем $stdout, которая по умолчанию заполняется константой 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