Как проверить, помещает ли 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.
Ответы
Ответ 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