RSpecで標準入出力をどんどんテストする。
paizaで1年前とけなかった問題がとけて嬉しがって回答コードをブログに載せたら当たり前のように怒られるという体験をしました。ごめんなさい。
ところで標準入出力のテストがしたくなった場合
- ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
- rspec 3.4.4
こういう標準入出力のあるやつに対して
最初の入力値が入力回数になる、Cの教科書などでもお馴染みの形式です。
#
# 本体
#
class Work
attr_accessor :data
def initialize(data)
self.data = data
end
def run
data.join('::')
end
end
#
# 入出力担当
#
class Keeper
class << self
def run
total_input = STDIN.gets.to_i
data = (1..total_input).to_a.map do
STDIN.gets.chomp
end
STDOUT.puts(Work.new(data).run)
end
end
end
#
# ruby ./std.rb された時のみ
#
if __FILE__ == $0
Keeper.run
end
こんな感じでスタブしておいて
require './std.rb'
require 'rspec'
describe do
let(:input) { @input }
before :each do
allow(STDIN).to receive(:gets) do
input.shift.to_s + "\n"
end
allow(STDOUT).to receive(:puts) do |val|
val.to_s + "\n"
end
end
# 下記のテストが入る
end
テストはこんな感じで
@input
に入力値を配列で設定します。
describe '入力した文字が連結されて帰ってくる' do
it do
@input = %w(3 a b c)
expect(Keeper.run).to eq("a::b::c\n")
end
it do
@input = %w(4 b c a a)
expect(Keeper.run).to eq("b::c::a::a\n")
end
end
exampleがすっきりしているのがタイトルのどんどんっぽい部分です。
テスト
$ rspec std_spec.rb
入力した文字が連結されて帰ってくる
should eq "a::b::c\n"
should eq "b::c::a::a\n"
Finished in 0.00484 seconds (files took 0.0609 seconds to load)
2 examples, 0 failures
標準入出力のケツには改行が入るので、それを意識するのがコツと言えばコツです。
ところでoutput().to_stdout
というのがある
puts
ではなくSTDOUT.puts
を使っていると、以下の記法ではexpected block to output "b::c::a::a\n" to stdout, but output nothing
になります。
expect { Keeper.run }.to output("b::c::a::a\n").to_stdout
puts
だとどっちでもOK。
うーん?