RSpecで試行錯誤
RSpecを--format documentation
を付けて実行したときに、結果がいい感じになるように工夫した過程。(だいたい)
最初
describe MatchAddress do describe '#call' do describe '000-0000' do address = described_class.new('000-0000').call it { expect(address).to eq 'True' } end end end
output
MatchAddress #call 000-0000 should eq "True"
outputは悪くないけど、他の数字のケースでspecを書くのがめんどくさそうだ。また、重複する処理もある。
次: shared_examples使ってみよう
shared_examples_for 'valid address' do let(:address) { described_class.new(input).call } it { expect(address).to eq 'True' } end describe MatchAddress do describe '#call' do describe '000-0000' do it_behaves_like 'valid address' do let(:input) { '000-0000' } end end end end
output
MatchIPv4Address #call 000-0000 behaves like valid address should eq "True"
複数ケースを少しでもDRYに書けるようになったのはよくなったかもしれないが、outputがよくない。
次: カスタムマッチャ作ってみる
describe MatchAddress do describe '#call' do describe '000-0000' do it { is_expected.to be_a_valid_address } end end end RSpec::Matchers.define :be_a_valid_address do match do |actual| MatchAddress.new(actual).call == 'True' end end
output 怒られる
MatchIPv4Address #call "000-0000" example at ./match_address_spec.rb:18 (FAILED - 1) 1) MatchAddress#call 000-0000 Failure/Error: it { is_expected.to be_a_valid_address } ArgumentError: wrong number of arguments (0 for 1)
ほんとはこうなって欲しかった
MatchAddress #call "000-0000" should be a valid address
原因は、describe
は引数が文字列だとsubject
を置き換えないから。
is_expected
はexpected(subject)
が呼ばれているだけなので、カスタムマッチャのmatch
のブロック引数には000-0000
はこない。
describe MatchAddress do describe '#call' do describe :'000-0000' do it { is_expected.to be_a_valid_address } end end end
'000-0000'
を:'000-0000'
とシンボルにしてみる。
output
MatchAddress #call "000-0000" should be a valid address
できた。でも:'000-0000'
とか微妙だし、ケースごとにdescribe
書くのもなんだかな。
次 describe
を削ってみる
describe MatchAddress do describe '#call' do specify('000-0000') { expect('000-0000').to be_a_valid_address } end end
すっきりした。でも output
MatchAddress #call "000-0000"
わからん。it
(specify
)は、引数があるとoutputにその文字列が、ないと中身(ここではshould be a valid address
)が表示される。
でも書き方は気に入った。
次: 000-0000
2回書くのが嫌だな
it { expect(address).to be_a_valid_IPv4_address }
にしてみる output
MatchAddress #call should be a valid address
なるほど、わからん。
引数があるとoutputにその文字列が、ないと中身(ここでは
should be a valid address
)が表示される。
だからだ。そして、暗黙的なsubject
は表示されない。
結論
describe MatchAddress do describe '#call' do describe 'valid addresses' do %w(000-0000 2551024).each do |address| specify(address) { expect(address).to be_a_valid_address } end end end RSpec::Matchers.define :be_a_valid_address do match do |actual| MatchAddress.new(actual).call == 'True' end end
output
MatchAddress #call valid addresses 000-0000 2551024
まぁ、少しoutputがイレギュラーな感じもするけど、分かるからいいんじゃないだろうか。 最終的にこんな感じで表示されると思う。
MatchAddress #call valid addresses 000-0000 2551024 invalid addresses 000ー0000 000-000 000-00000
その他
MatchAddress #call 000-0000 should be a valid address 255-1024 should be a valid address
みたいな結果がいい人は
describe MatchAddress do describe '#call' do %w(000-0000 255-1024).each do |address| describe address do # 明示的に`subject`を指定しないと`MatchAddress`が呼びだされる。 subject { address } it { is_expected.to be_a_valid_address } end end end end
もありかもしれない。でも、テストでeach
使わない方が良いと思うなどの場合は、少し長い書き方だ。
感想
カスタムマッチャ、あまりつかってなかったけど、--format documentation
で実行したら必要性と便利さがわかった。
今度から使おう。